Skip to content

Commit

Permalink
perf buildid-cache: Add ability to add kcore to the cache
Browse files Browse the repository at this point in the history
kcore can be used to view the running kernel object code.  However,
kcore changes as modules are loaded and unloaded, and when the kernel
decides to modify its own code.  Consequently it is useful to create a
copy of kcore at a particular time.  Unlike vmlinux, kcore is not unique
for a given build-id.  And in addition, the kallsyms and modules files
are also needed.  The tool therefore creates a directory:

	~/.debug/[kernel.kcore]/<build-id>/<YYYYmmddHHMMSShh>

which contains: kcore, kallsyms and modules.

Note that the copied kcore contains only code sections.  See the
kcore_copy() function for how that is determined.

The tool will not make additional copies of kcore if there is already
one with the same modules at the same addresses.

Currently, perf tools will not look for kcore in the cache.  That is
addressed in another patch.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/525BF849.5030405@intel.com
[ renamed 'index' to 'idx' to avoid shadowing string.h symbol in f12,
  use at least one member initializer when initializing a struct to
  zeros, also to fix the build on f12 ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Adrian Hunter authored and Arnaldo Carvalho de Melo committed Oct 14, 2013
1 parent 1179e11 commit fc1b691
Show file tree
Hide file tree
Showing 6 changed files with 576 additions and 1 deletion.
13 changes: 13 additions & 0 deletions tools/perf/Documentation/perf-buildid-cache.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ OPTIONS
-a::
--add=::
Add specified file to the cache.
-k::
--kcore::
Add specified kcore file to the cache. For the current host that is
/proc/kcore which requires root permissions to read. Be aware that
running 'perf buildid-cache' as root may update root's build-id cache
not the user's. Use the -v option to see where the file is created.
Note that the copied file contains only code sections not the whole core
image. Note also that files "kallsyms" and "modules" must also be in the
same directory and are also copied. All 3 files are created with read
permissions for root only. kcore will not be added if there is already a
kcore in the cache (with the same build-id) that has the same modules at
the same addresses. Use the -v option to see if a copy of kcore is
actually made.
-r::
--remove=::
Remove specified file from the cache.
Expand Down
148 changes: 147 additions & 1 deletion tools/perf/builtin-buildid-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
* Copyright (C) 2010, Red Hat Inc.
* Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
*/
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <dirent.h>
#include <unistd.h>
#include "builtin.h"
#include "perf.h"
#include "util/cache.h"
Expand All @@ -17,6 +22,140 @@
#include "util/session.h"
#include "util/symbol.h"

static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
{
char root_dir[PATH_MAX];
char notes[PATH_MAX];
u8 build_id[BUILD_ID_SIZE];
char *p;

strlcpy(root_dir, proc_dir, sizeof(root_dir));

p = strrchr(root_dir, '/');
if (!p)
return -1;
*p = '\0';

scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);

if (sysfs__read_build_id(notes, build_id, sizeof(build_id)))
return -1;

build_id__sprintf(build_id, sizeof(build_id), sbuildid);

return 0;
}

static int build_id_cache__kcore_dir(char *dir, size_t sz)
{
struct timeval tv;
struct tm tm;
char dt[32];

if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
return -1;

if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
return -1;

scnprintf(dir, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);

return 0;
}

static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
size_t to_dir_sz)
{
char from[PATH_MAX];
char to[PATH_MAX];
struct dirent *dent;
int ret = -1;
DIR *d;

d = opendir(to_dir);
if (!d)
return -1;

scnprintf(from, sizeof(from), "%s/modules", from_dir);

while (1) {
dent = readdir(d);
if (!dent)
break;
if (dent->d_type != DT_DIR)
continue;
scnprintf(to, sizeof(to), "%s/%s/modules", to_dir,
dent->d_name);
if (!compare_proc_modules(from, to)) {
scnprintf(to, sizeof(to), "%s/%s", to_dir,
dent->d_name);
strlcpy(to_dir, to, to_dir_sz);
ret = 0;
break;
}
}

closedir(d);

return ret;
}

static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
{
char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
char from_dir[PATH_MAX], to_dir[PATH_MAX];
char *p;

strlcpy(from_dir, filename, sizeof(from_dir));

p = strrchr(from_dir, '/');
if (!p || strcmp(p + 1, "kcore"))
return -1;
*p = '\0';

if (build_id_cache__kcore_buildid(from_dir, sbuildid))
return -1;

scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
debugdir, sbuildid);

if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
pr_debug("same kcore found in %s\n", to_dir);
return 0;
}

if (build_id_cache__kcore_dir(dir, sizeof(dir)))
return -1;

scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s",
debugdir, sbuildid, dir);

if (mkdir_p(to_dir, 0755))
return -1;

if (kcore_copy(from_dir, to_dir)) {
/* Remove YYYYmmddHHMMSShh directory */
if (!rmdir(to_dir)) {
p = strrchr(to_dir, '/');
if (p)
*p = '\0';
/* Try to remove buildid directory */
if (!rmdir(to_dir)) {
p = strrchr(to_dir, '/');
if (p)
*p = '\0';
/* Try to remove [kernel.kcore] directory */
rmdir(to_dir);
}
}
return -1;
}

pr_debug("kcore added to build-id cache directory %s\n", to_dir);

return 0;
}

static int build_id_cache__add_file(const char *filename, const char *debugdir)
{
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Expand Down Expand Up @@ -130,11 +269,14 @@ int cmd_buildid_cache(int argc, const char **argv,
char const *add_name_list_str = NULL,
*remove_name_list_str = NULL,
*missing_filename = NULL,
*update_name_list_str = NULL;
*update_name_list_str = NULL,
*kcore_filename;

const struct option buildid_cache_options[] = {
OPT_STRING('a', "add", &add_name_list_str,
"file list", "file(s) to add"),
OPT_STRING('k', "kcore", &kcore_filename,
"file", "kcore file to add"),
OPT_STRING('r', "remove", &remove_name_list_str, "file list",
"file(s) to remove"),
OPT_STRING('M', "missing", &missing_filename, "file",
Expand Down Expand Up @@ -217,5 +359,9 @@ int cmd_buildid_cache(int argc, const char **argv,
}
}

if (kcore_filename &&
build_id_cache__add_kcore(kcore_filename, debugdir))
pr_warning("Couldn't add %s\n", kcore_filename);

return ret;
}
Loading

0 comments on commit fc1b691

Please sign in to comment.