00001
00012 #include "opd_sfile.h"
00013
00014 #include "opd_trans.h"
00015 #include "opd_kernel.h"
00016 #include "opd_mangling.h"
00017 #include "opd_anon.h"
00018 #include "opd_printf.h"
00019 #include "opd_stats.h"
00020 #include "opd_extended.h"
00021 #include "oprofiled.h"
00022
00023 #include "op_libiberty.h"
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 #include <sys/stat.h>
00030 #include <fcntl.h>
00031
00032 #define HASH_SIZE 2048
00033 #define HASH_BITS (HASH_SIZE - 1)
00034
00036 static struct list_head hashes[HASH_SIZE];
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 static struct list_head kernel_cmdlines[HASH_SIZE];
00076 struct kern_cmdline {
00077 pid_t kern_pid;
00078 struct list_head hash;
00079 unsigned int has_cmdline;
00080 };
00081
00083 static LIST_HEAD(lru_list);
00084
00085
00086
00088 static unsigned long
00089 sfile_hash(struct transient const * trans, struct kernel_image * ki)
00090 {
00091 unsigned long val = 0;
00092
00093 if (separate_thread) {
00094 val ^= trans->tid << 2;
00095 val ^= trans->tgid << 2;
00096 }
00097
00098 if (separate_kernel || ((trans->anon || separate_lib) && !ki))
00099 val ^= trans->app_cookie >> (DCOOKIE_SHIFT + 3);
00100
00101 if (separate_cpu)
00102 val ^= trans->cpu;
00103
00104
00105 if (trans->in_kernel) {
00106 val ^= ki->start >> 14;
00107 val ^= ki->end >> 7;
00108 return val & HASH_BITS;
00109 }
00110
00111 if (trans->cookie != NO_COOKIE) {
00112 val ^= trans->cookie >> DCOOKIE_SHIFT;
00113 return val & HASH_BITS;
00114 }
00115
00116 if (!separate_thread)
00117 val ^= trans->tgid << 2;
00118
00119 if (trans->anon) {
00120 val ^= trans->anon->start >> VMA_SHIFT;
00121 val ^= trans->anon->end >> (VMA_SHIFT + 1);
00122 }
00123
00124 return val & HASH_BITS;
00125 }
00126
00127
00128 static int
00129 do_match(struct sfile const * sf, cookie_t cookie, cookie_t app_cookie,
00130 struct kernel_image const * ki, struct anon_mapping const * anon,
00131 pid_t tgid, pid_t tid, unsigned int cpu)
00132 {
00133
00134
00135
00136
00137 if (sf->kernel != ki)
00138 return 0;
00139
00140 if (separate_thread) {
00141 if (sf->tid != tid || sf->tgid != tgid)
00142 return 0;
00143 }
00144
00145 if (separate_cpu) {
00146 if (sf->cpu != cpu)
00147 return 0;
00148 }
00149
00150 if (separate_kernel || ((anon || separate_lib) && !ki)) {
00151 if (sf->app_cookie != app_cookie)
00152 return 0;
00153 }
00154
00155
00156
00157
00158 if (ki)
00159 return 1;
00160
00161 if (sf->anon != anon)
00162 return 0;
00163
00164 return sf->cookie == cookie;
00165 }
00166
00167
00168 static int
00169 trans_match(struct transient const * trans, struct sfile const * sfile,
00170 struct kernel_image const * ki)
00171 {
00172 return do_match(sfile, trans->cookie, trans->app_cookie, ki,
00173 trans->anon, trans->tgid, trans->tid, trans->cpu);
00174 }
00175
00176
00177 int
00178 sfile_equal(struct sfile const * sf, struct sfile const * sf2)
00179 {
00180 return do_match(sf, sf2->cookie, sf2->app_cookie, sf2->kernel,
00181 sf2->anon, sf2->tgid, sf2->tid, sf2->cpu);
00182 }
00183
00184
00185 static int
00186 is_sf_ignored(struct sfile const * sf)
00187 {
00188 if (sf->kernel) {
00189 if (!is_image_ignored(sf->kernel->name))
00190 return 0;
00191
00192
00193
00194
00195 return is_cookie_ignored(sf->app_cookie);
00196 }
00197
00198
00199
00200
00201 if (sf->anon || is_cookie_ignored(sf->cookie))
00202 return is_cookie_ignored(sf->app_cookie);
00203
00204 return 0;
00205 }
00206
00207
00209 static struct sfile *
00210 create_sfile(unsigned long hash, struct transient const * trans,
00211 struct kernel_image * ki)
00212 {
00213 size_t i;
00214 struct sfile * sf;
00215
00216 sf = xmalloc(sizeof(struct sfile));
00217
00218 sf->hashval = hash;
00219
00220
00221
00222
00223 sf->cookie = trans->in_kernel ? INVALID_COOKIE : trans->cookie;
00224 sf->app_cookie = INVALID_COOKIE;
00225 sf->tid = (pid_t)-1;
00226 sf->tgid = (pid_t)-1;
00227 sf->cpu = 0;
00228 sf->kernel = ki;
00229 sf->anon = trans->anon;
00230
00231 for (i = 0 ; i < op_nr_counters ; ++i)
00232 odb_init(&sf->files[i]);
00233
00234 if (trans->ext)
00235 opd_ext_sfile_create(sf);
00236 else
00237 sf->ext_files = NULL;
00238
00239 for (i = 0; i < CG_HASH_SIZE; ++i)
00240 list_init(&sf->cg_hash[i]);
00241
00242 if (separate_thread)
00243 sf->tid = trans->tid;
00244 if (separate_thread || trans->cookie == NO_COOKIE)
00245 sf->tgid = trans->tgid;
00246
00247 if (separate_cpu)
00248 sf->cpu = trans->cpu;
00249
00250 if (separate_kernel || ((trans->anon || separate_lib) && !ki))
00251 sf->app_cookie = trans->app_cookie;
00252
00253 sf->ignored = is_sf_ignored(sf);
00254
00255 sf->embedded_offset = trans->embedded_offset;
00256
00257
00258
00259
00260
00261 if (trans->embedded_offset != UNUSED_EMBEDDED_OFFSET)
00262 sf->app_cookie = trans->app_cookie;
00263 return sf;
00264 }
00265
00266
00267 struct sfile * sfile_find(struct transient const * trans)
00268 {
00269 struct sfile * sf;
00270 struct list_head * pos;
00271 struct kernel_image * ki = NULL;
00272 unsigned long hash;
00273
00274
00275
00276
00277 if (trans->in_kernel == -1) {
00278 verbprintf(vsamples, "Losing sample at 0x%llx of unknown provenance.\n",
00279 trans->pc);
00280 opd_stats[OPD_NO_CTX]++;
00281 return NULL;
00282 }
00283
00284
00285 if (trans->in_kernel) {
00286 ki = find_kernel_image(trans);
00287 if (!ki) {
00288 verbprintf(vsamples, "Lost kernel sample %llx\n", trans->pc);
00289 opd_stats[OPD_LOST_KERNEL]++;
00290 return NULL;
00291 }
00292
00293
00294 if ((trans->tgid == 0) || (trans->tgid == 1) || (trans->tgid == 2))
00295 goto find_sfile;
00296
00297
00298
00299
00300 if (trans->app_cookie == NO_COOKIE) {
00301 int found = 0;
00302 struct kern_cmdline * kcmd;
00303 hash = (trans->tgid << 2) & HASH_BITS;
00304 list_for_each(pos, &kernel_cmdlines[hash]) {
00305 kcmd = list_entry(pos, struct kern_cmdline, hash);
00306 if (kcmd->kern_pid == trans->tgid) {
00307 found = 1;
00308 if (kcmd->has_cmdline) {
00309 verbprintf(vsamples,
00310 "Dropping user context kernel sample 0x%llx "
00311 "for process %u due to no app cookie available.\n",
00312 (unsigned long long)trans->pc, trans->tgid);
00313 opd_stats[OPD_NO_APP_KERNEL_SAMPLE]++;
00314 return NULL;
00315 }
00316 break;
00317 }
00318 }
00319 if (!found) {
00320 char name[32], dst[8];
00321 int fd, dropped = 0;
00322 kcmd = (struct kern_cmdline *)xmalloc(sizeof(*kcmd));
00323 kcmd->kern_pid = trans->tgid;
00324 snprintf(name, sizeof name, "/proc/%u/cmdline", trans->tgid);
00325 fd = open(name, O_RDONLY);
00326 if(fd==-1) {
00327
00328 kcmd->has_cmdline = 1;
00329 verbprintf(vsamples,
00330 "Open of /proc/%u/cmdline failed, so dropping "
00331 "kernel sameple 0x%llx\n",
00332 trans->tgid, (unsigned long long)trans->pc);
00333 opd_stats[OPD_NO_APP_KERNEL_SAMPLE]++;
00334 dropped = 1;
00335 } else {
00336 if((read(fd, dst, 8) < 1)) {
00337 verbprintf(vsamples, "No cmdline for PID %u\n", trans->tgid);
00338 kcmd->has_cmdline = 0;
00339 } else {
00340
00341
00342 dst[7] = '\0';
00343 verbprintf(vsamples, "Start of cmdline for PID %u is %s\n", trans->tgid, dst);
00344 kcmd->has_cmdline = 1;
00345 opd_stats[OPD_NO_APP_KERNEL_SAMPLE]++;
00346 dropped = 1;
00347 }
00348 }
00349 list_add(&kcmd->hash, &kernel_cmdlines[hash]);
00350 if (dropped)
00351 return NULL;
00352 }
00353 }
00354 } else if (trans->cookie == NO_COOKIE && !trans->anon) {
00355 if (vsamples) {
00356 char const * app = verbose_cookie(trans->app_cookie);
00357 printf("No anon map for pc %llx, app %s.\n",
00358 trans->pc, app);
00359 }
00360 opd_stats[OPD_LOST_NO_MAPPING]++;
00361 return NULL;
00362 }
00363
00364 find_sfile:
00365 hash = sfile_hash(trans, ki);
00366 list_for_each(pos, &hashes[hash]) {
00367 sf = list_entry(pos, struct sfile, hash);
00368 if (trans_match(trans, sf, ki)) {
00369 sfile_get(sf);
00370 goto lru;
00371 }
00372 }
00373
00374 sf = create_sfile(hash, trans, ki);
00375 list_add(&sf->hash, &hashes[hash]);
00376
00377 lru:
00378 sfile_put(sf);
00379 return sf;
00380 }
00381
00382
00383 void sfile_dup(struct sfile * to, struct sfile * from)
00384 {
00385 size_t i;
00386
00387 memcpy(to, from, sizeof (struct sfile));
00388
00389 for (i = 0 ; i < op_nr_counters ; ++i)
00390 odb_init(&to->files[i]);
00391
00392 opd_ext_sfile_dup(to, from);
00393
00394 for (i = 0; i < CG_HASH_SIZE; ++i)
00395 list_init(&to->cg_hash[i]);
00396
00397 list_init(&to->hash);
00398 list_init(&to->lru);
00399 }
00400
00401
00402 static odb_t * get_file(struct transient const * trans, int is_cg)
00403 {
00404 struct sfile * sf = trans->current;
00405 struct sfile * last = trans->last;
00406 struct cg_entry * cg;
00407 struct list_head * pos;
00408 unsigned long hash;
00409 odb_t * file;
00410
00411 if ((trans->ext) != NULL)
00412 return opd_ext_sfile_get(trans, is_cg);
00413
00414 if (trans->event >= op_nr_counters) {
00415 fprintf(stderr, "%s: Invalid counter %lu\n", __FUNCTION__,
00416 trans->event);
00417 abort();
00418 }
00419
00420 file = &sf->files[trans->event];
00421
00422 if (!is_cg)
00423 goto open;
00424
00425 hash = last->hashval & (CG_HASH_SIZE - 1);
00426
00427
00428
00429
00430 list_for_each(pos, &sf->cg_hash[hash]) {
00431 cg = list_entry(pos, struct cg_entry, hash);
00432 if (sfile_equal(last, &cg->to)) {
00433 file = &cg->to.files[trans->event];
00434 goto open;
00435 }
00436 }
00437
00438 cg = xmalloc(sizeof(struct cg_entry));
00439 sfile_dup(&cg->to, last);
00440 list_add(&cg->hash, &sf->cg_hash[hash]);
00441 file = &cg->to.files[trans->event];
00442
00443 open:
00444 if (!odb_open_count(file))
00445 opd_open_sample_file(file, last, sf, trans->event, is_cg);
00446
00447
00448 if (!odb_open_count(file))
00449 return NULL;
00450
00451 return file;
00452 }
00453
00454
00455 static void verbose_print_sample(struct sfile * sf, vma_t pc, uint counter)
00456 {
00457 char const * app = verbose_cookie(sf->app_cookie);
00458 printf("0x%llx(%u): ", pc, counter);
00459 if (sf->anon) {
00460 printf("anon (tgid %u, 0x%llx-0x%llx), ",
00461 (unsigned int)sf->anon->tgid,
00462 sf->anon->start, sf->anon->end);
00463 } else if (sf->kernel) {
00464 printf("kern (name %s, 0x%llx-0x%llx), ", sf->kernel->name,
00465 sf->kernel->start, sf->kernel->end);
00466 } else {
00467 printf("%s(%llx), ", verbose_cookie(sf->cookie), sf->cookie);
00468 }
00469 printf("app %s(%llx)", app, sf->app_cookie);
00470 }
00471
00472
00473 static void verbose_sample(struct transient const * trans, vma_t pc)
00474 {
00475 printf("Sample ");
00476 verbose_print_sample(trans->current, pc, trans->event);
00477 printf("\n");
00478 }
00479
00480
00481 static void
00482 verbose_arc(struct transient const * trans, vma_t from, vma_t to)
00483 {
00484 printf("Arc ");
00485 verbose_print_sample(trans->current, from, trans->event);
00486 printf(" -> 0x%llx", to);
00487 printf("\n");
00488 }
00489
00490
00491 static void sfile_log_arc(struct transient const * trans)
00492 {
00493 int err;
00494 vma_t from = trans->pc;
00495 vma_t to = trans->last_pc;
00496 uint64_t key;
00497 odb_t * file;
00498
00499 file = get_file(trans, 1);
00500
00501
00502 if (trans->current->kernel)
00503 from -= trans->current->kernel->start;
00504
00505 if (trans->last->kernel)
00506 to -= trans->last->kernel->start;
00507
00508 if (trans->current->anon)
00509 from -= trans->current->anon->start;
00510
00511 if (trans->last->anon)
00512 to -= trans->last->anon->start;
00513
00514 if (varcs)
00515 verbose_arc(trans, from, to);
00516
00517 if (!file) {
00518 opd_stats[OPD_LOST_SAMPLEFILE]++;
00519 return;
00520 }
00521
00522
00523 key = to & (0xffffffff);
00524 key |= ((uint64_t)from) << 32;
00525
00526 err = odb_update_node(file, key);
00527 if (err) {
00528 fprintf(stderr, "%s: %s\n", __FUNCTION__, strerror(err));
00529 abort();
00530 }
00531 }
00532
00533
00534 void sfile_log_sample(struct transient const * trans)
00535 {
00536 sfile_log_sample_count(trans, 1);
00537 }
00538
00539
00540 void sfile_log_sample_count(struct transient const * trans,
00541 unsigned long int count)
00542 {
00543 int err;
00544 vma_t pc = trans->pc;
00545 odb_t * file;
00546
00547 if (trans->tracing == TRACING_ON) {
00548
00549
00550 if (trans->last)
00551 sfile_log_arc(trans);
00552 return;
00553 }
00554
00555 file = get_file(trans, 0);
00556
00557
00558 if (trans->current->kernel)
00559 pc -= trans->current->kernel->start;
00560
00561 if (trans->current->anon)
00562 pc -= trans->current->anon->start;
00563
00564 if (vsamples)
00565 verbose_sample(trans, pc);
00566
00567 if (!file) {
00568 opd_stats[OPD_LOST_SAMPLEFILE]++;
00569 return;
00570 }
00571
00572 err = odb_update_node_with_offset(file,
00573 (odb_key_t)pc,
00574 count);
00575 if (err) {
00576 fprintf(stderr, "%s: %s\n", __FUNCTION__, strerror(err));
00577 abort();
00578 }
00579 }
00580
00581
00582 static int close_sfile(struct sfile * sf, void * data __attribute__((unused)))
00583 {
00584 size_t i;
00585
00586
00587 for (i = 0; i < op_nr_counters; ++i)
00588 odb_close(&sf->files[i]);
00589
00590 opd_ext_sfile_close(sf);
00591
00592 return 0;
00593 }
00594
00595
00596 static void kill_sfile(struct sfile * sf)
00597 {
00598 close_sfile(sf, NULL);
00599 list_del(&sf->hash);
00600 list_del(&sf->lru);
00601 }
00602
00603
00604 static int sync_sfile(struct sfile * sf, void * data __attribute__((unused)))
00605 {
00606 size_t i;
00607
00608 for (i = 0; i < op_nr_counters; ++i)
00609 odb_sync(&sf->files[i]);
00610
00611 opd_ext_sfile_sync(sf);
00612
00613 return 0;
00614 }
00615
00616
00617 static int is_sfile_kernel(struct sfile * sf, void * data __attribute__((unused)))
00618 {
00619 return !!sf->kernel;
00620 }
00621
00622
00623 static int is_sfile_anon(struct sfile * sf, void * data)
00624 {
00625 return sf->anon == data;
00626 }
00627
00628
00629 typedef int (*sfile_func)(struct sfile *, void *);
00630
00631 static void
00632 for_one_sfile(struct sfile * sf, sfile_func func, void * data)
00633 {
00634 size_t i;
00635 int free_sf = func(sf, data);
00636
00637 for (i = 0; i < CG_HASH_SIZE; ++i) {
00638 struct list_head * pos;
00639 struct list_head * pos2;
00640 list_for_each_safe(pos, pos2, &sf->cg_hash[i]) {
00641 struct cg_entry * cg =
00642 list_entry(pos, struct cg_entry, hash);
00643 if (free_sf || func(&cg->to, data)) {
00644 kill_sfile(&cg->to);
00645 list_del(&cg->hash);
00646 free(cg);
00647 }
00648 }
00649 }
00650
00651 if (free_sf) {
00652 kill_sfile(sf);
00653 free(sf);
00654 }
00655 }
00656
00657
00658 static void for_each_sfile(sfile_func func, void * data)
00659 {
00660 struct list_head * pos;
00661 struct list_head * pos2;
00662
00663 list_for_each_safe(pos, pos2, &lru_list) {
00664 struct sfile * sf = list_entry(pos, struct sfile, lru);
00665 for_one_sfile(sf, func, data);
00666 }
00667 }
00668
00669
00670 void sfile_clear_kernel(void)
00671 {
00672 for_each_sfile(is_sfile_kernel, NULL);
00673 }
00674
00675
00676 void sfile_clear_anon(struct anon_mapping * anon)
00677 {
00678 for_each_sfile(is_sfile_anon, anon);
00679 }
00680
00681
00682 void sfile_sync_files(void)
00683 {
00684 for_each_sfile(sync_sfile, NULL);
00685 }
00686
00687
00688 void sfile_close_files(void)
00689 {
00690 for_each_sfile(close_sfile, NULL);
00691 }
00692
00693
00694 static int always_true(void)
00695 {
00696 return 1;
00697 }
00698
00699
00700 #define LRU_AMOUNT 256
00701
00702
00703
00704
00705
00706
00707 int sfile_lru_clear(void)
00708 {
00709 struct list_head * pos;
00710 struct list_head * pos2;
00711 int amount = LRU_AMOUNT;
00712
00713 if (list_empty(&lru_list))
00714 return 1;
00715
00716 list_for_each_safe(pos, pos2, &lru_list) {
00717 struct sfile * sf;
00718 if (!--amount)
00719 break;
00720 sf = list_entry(pos, struct sfile, lru);
00721 for_one_sfile(sf, (sfile_func)always_true, NULL);
00722 }
00723
00724 return 0;
00725 }
00726
00727
00728 void sfile_get(struct sfile * sf)
00729 {
00730 if (sf)
00731 list_del(&sf->lru);
00732 }
00733
00734
00735 void sfile_put(struct sfile * sf)
00736 {
00737 if (sf)
00738 list_add_tail(&sf->lru, &lru_list);
00739 }
00740
00741
00742 void sfile_init(void)
00743 {
00744 size_t i = 0;
00745
00746 for (; i < HASH_SIZE; ++i) {
00747 list_init(&hashes[i]);
00748 list_init(&kernel_cmdlines[i]);
00749 }
00750 }