opd_ibs.c

Go to the documentation of this file.
00001 
00014 #include "op_hw_config.h"
00015 #include "op_events.h"
00016 #include "op_string.h"
00017 #include "op_hw_specific.h"
00018 #include "op_libiberty.h"
00019 #include "opd_printf.h"
00020 #include "opd_trans.h"
00021 #include "opd_events.h"
00022 #include "opd_kernel.h"
00023 #include "opd_anon.h"
00024 #include "opd_sfile.h"
00025 #include "opd_interface.h"
00026 #include "opd_mangling.h"
00027 #include "opd_extended.h"
00028 #include "opd_ibs.h"
00029 #include "opd_ibs_trans.h"
00030 #include "opd_ibs_macro.h"
00031 
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <errno.h>
00035 #include <string.h>
00036 #include <limits.h>
00037 
00038 extern op_cpu cpu_type;
00039 extern int no_event_ok;
00040 extern int sfile_equal(struct sfile const * sf, struct sfile const * sf2);
00041 extern void sfile_dup(struct sfile * to, struct sfile * from);
00042 extern char * session_dir;
00043 
00044 /* IBS Select Counters */
00045 static unsigned int ibs_selected_size;
00046 
00047 /* These flags store the IBS-derived events selection. */
00048 static unsigned int ibs_fetch_selected_flag;
00049 static unsigned int ibs_op_selected_flag;
00050 static unsigned int ibs_op_ls_selected_flag;
00051 static unsigned int ibs_op_nb_selected_flag;
00052 
00053 /* IBS Statistics */
00054 static unsigned long ibs_fetch_sample_stats;
00055 static unsigned long ibs_fetch_incomplete_stats;
00056 static unsigned long ibs_op_sample_stats;
00057 static unsigned long ibs_op_incomplete_stats;
00058 static unsigned long ibs_derived_event_stats;
00059 
00060 /*
00061  * IBS Virtual Counter
00062  */
00063 struct opd_event ibs_vc[OP_MAX_IBS_COUNTERS];
00064 
00065 /* IBS Virtual Counter Index(VCI) Map*/
00066 unsigned int ibs_vci_map[OP_MAX_IBS_COUNTERS];
00067 
00068 /* CPUID information */
00069 unsigned int ibs_family;
00070 unsigned int ibs_model;
00071 unsigned int ibs_stepping;
00072 
00073 /* IBS Extended MSRs */
00074 static unsigned long ibs_bta_enabled;
00075 
00076 /* IBS log files */
00077 FILE * memaccess_log;
00078 FILE * bta_log;
00079 
00085 static void opd_log_ibs_fetch(struct transient * trans)
00086 {
00087     struct ibs_fetch_sample * trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch;
00088     if (!trans_fetch)
00089         return;
00090 
00091     trans_ibs_fetch(trans, ibs_fetch_selected_flag);
00092 }
00093 
00094 
00099 static void opd_log_ibs_op(struct transient * trans)
00100 {
00101     struct ibs_op_sample * trans_op = ((struct ibs_sample*)(trans->ext))->op;
00102     if (!trans_op)
00103         return;
00104 
00105     trans_ibs_op_mask_reserved(ibs_family, trans);
00106 
00107     if (trans_ibs_op_rip_invalid(trans) != 0)
00108         return;
00109 
00110     trans_ibs_op(trans, ibs_op_selected_flag);
00111     trans_ibs_op_ls(trans, ibs_op_ls_selected_flag);
00112     trans_ibs_op_nb(trans, ibs_op_nb_selected_flag);
00113     trans_ibs_op_ls_memaccess(trans);
00114     trans_ibs_op_bta(trans);
00115 }
00116 
00117 
00118 static void opd_put_ibs_sample(struct transient * trans)
00119 {
00120     unsigned long long event = 0;
00121     struct kernel_image * k_image = NULL;
00122     struct ibs_fetch_sample * trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch;
00123 
00124     if (!enough_remaining(trans, 1)) {
00125         trans->remaining = 0;
00126         return;
00127     }
00128 
00129     /* IBS can generate samples with invalid dcookie and
00130      * in kernel address range. Map such samples to vmlinux
00131      * only if the user either specifies a range, or vmlinux.
00132      */
00133     if (trans->cookie == INVALID_COOKIE
00134         && (k_image = find_kernel_image(trans)) != NULL
00135         && (k_image->start != 0 && k_image->end != 0)
00136         && trans->in_kernel == 0)
00137         trans->in_kernel = 1;
00138 
00139     if (trans->tracing != TRACING_ON)
00140         trans->event = event;
00141 
00142     /* sfile can change at each sample for kernel */
00143     if (trans->in_kernel != 0)
00144         clear_trans_current(trans);
00145 
00146     if (!trans->in_kernel && trans->cookie == NO_COOKIE)
00147         trans->anon = find_anon_mapping(trans);
00148 
00149     /* get the current sfile if needed */
00150     if (!trans->current)
00151         trans->current = sfile_find(trans);
00152 
00153     /*
00154      * can happen if kernel sample falls through the cracks, or if
00155      * it's a sample from an anon region we couldn't find
00156      */
00157     if (!trans->current)
00158         goto out;
00159 
00160     if (trans_fetch)
00161         opd_log_ibs_fetch(trans);
00162     else
00163         opd_log_ibs_op(trans);
00164 out:
00165     /* switch to trace mode */
00166     if (trans->tracing == TRACING_START)
00167         trans->tracing = TRACING_ON;
00168 
00169     update_trans_last(trans);
00170 }
00171 
00172 
00173 static void get_ibs_bta_status()
00174 {
00175     FILE * fp = NULL;
00176     char buf[PATH_MAX];
00177 
00178     /* Default to disable */
00179     ibs_bta_enabled = 0;
00180 
00181     snprintf(buf, PATH_MAX, "/dev/oprofile/ibs_op/branch_target");
00182     fp = fopen(buf, "r");
00183     if (!fp)
00184         return;
00185 
00186     while (fgets(buf, PATH_MAX, fp) != NULL)
00187         ibs_bta_enabled = strtoul(buf, NULL, 10);   
00188 
00189     fclose(fp);
00190 }
00191 
00192 
00193 void code_ibs_fetch_sample(struct transient * trans)
00194 {
00195     struct ibs_fetch_sample * trans_fetch = NULL;
00196 
00197     if (!enough_remaining(trans, 7)) {
00198         verbprintf(vext, "not enough remaining\n");
00199         trans->remaining = 0;
00200         ibs_fetch_incomplete_stats++;
00201         return;
00202     }
00203 
00204     ibs_fetch_sample_stats++;
00205 
00206     trans->ext = xmalloc(sizeof(struct ibs_sample));
00207     ((struct ibs_sample*)(trans->ext))->fetch = xmalloc(sizeof(struct ibs_fetch_sample));
00208     trans_fetch = ((struct ibs_sample*)(trans->ext))->fetch;
00209 
00210     trans_fetch->rip = pop_buffer_value(trans);
00211 
00212     trans_fetch->ibs_fetch_lin_addr_low   = pop_buffer_value(trans);
00213     trans_fetch->ibs_fetch_lin_addr_high  = pop_buffer_value(trans);
00214 
00215     trans_fetch->ibs_fetch_ctl_low        = pop_buffer_value(trans);
00216     trans_fetch->ibs_fetch_ctl_high       = pop_buffer_value(trans);
00217     trans_fetch->ibs_fetch_phys_addr_low  = pop_buffer_value(trans);
00218     trans_fetch->ibs_fetch_phys_addr_high = pop_buffer_value(trans);
00219 
00220     verbprintf(vsamples,
00221         "FETCH_X CPU:%ld PID:%ld RIP:%lx CTL_H:%x LAT:%d P_HI:%x P_LO:%x L_HI:%x L_LO:%x\n",
00222         trans->cpu,
00223         (long)trans->tgid,
00224         trans_fetch->rip,
00225         (trans_fetch->ibs_fetch_ctl_high >> 16) & 0x3ff,
00226         (trans_fetch->ibs_fetch_ctl_high) & 0xffff,
00227         trans_fetch->ibs_fetch_phys_addr_high,
00228         trans_fetch->ibs_fetch_phys_addr_low,
00229         trans_fetch->ibs_fetch_lin_addr_high,
00230         trans_fetch->ibs_fetch_lin_addr_low) ;
00231 
00232     /* Overwrite the trans->pc with the more accurate trans_fetch->rip */
00233     trans->pc = trans_fetch->rip;
00234 
00235     opd_put_ibs_sample(trans);
00236 
00237     free(trans_fetch);
00238     free(trans->ext);
00239     trans->ext = NULL;
00240 }
00241 
00242 
00243 static void get_ibs_op_bta_sample(struct transient * trans,
00244                     struct ibs_op_sample * trans_op)
00245 {
00246     // Check remaining
00247     if (!enough_remaining(trans, 2)) {
00248         verbprintf(vext, "not enough remaining\n");
00249         trans->remaining = 0;
00250         ibs_op_incomplete_stats++;
00251         return;
00252     }
00253 
00254     if (ibs_bta_enabled == 1) {
00255         trans_op->ibs_op_brtgt_addr = pop_buffer_value(trans);
00256     
00257         // Check if branch target address is valid (MSRC001_1035[37] == 1]
00258         if ((trans_op->ibs_op_data1_high & (0x00000001 << 5)) == 0) {
00259             trans_op->ibs_op_brtgt_addr = 0;
00260         }
00261     } else {
00262         trans_op->ibs_op_brtgt_addr = 0;
00263     }
00264 }
00265 
00266 
00267 void code_ibs_op_sample(struct transient * trans)
00268 {
00269     struct ibs_op_sample * trans_op= NULL;
00270 
00271     if (!enough_remaining(trans, 13)) {
00272         verbprintf(vext, "not enough remaining\n");
00273         trans->remaining = 0;
00274         ibs_op_incomplete_stats++;
00275         return;
00276     }
00277 
00278     ibs_op_sample_stats++;
00279 
00280     trans->ext = xmalloc(sizeof(struct ibs_sample));
00281     ((struct ibs_sample*)(trans->ext))->op = xmalloc(sizeof(struct ibs_op_sample));
00282     trans_op = ((struct ibs_sample*)(trans->ext))->op;
00283 
00284     trans_op->rip = pop_buffer_value(trans);
00285 
00286     trans_op->ibs_op_lin_addr_low = pop_buffer_value(trans);
00287     trans_op->ibs_op_lin_addr_high = pop_buffer_value(trans);
00288 
00289     trans_op->ibs_op_data1_low         = pop_buffer_value(trans);
00290     trans_op->ibs_op_data1_high        = pop_buffer_value(trans);
00291     trans_op->ibs_op_data2_low         = pop_buffer_value(trans);
00292     trans_op->ibs_op_data2_high        = pop_buffer_value(trans);
00293     trans_op->ibs_op_data3_low         = pop_buffer_value(trans);
00294     trans_op->ibs_op_data3_high        = pop_buffer_value(trans);
00295     trans_op->ibs_op_ldst_linaddr_low  = pop_buffer_value(trans);
00296     trans_op->ibs_op_ldst_linaddr_high = pop_buffer_value(trans);
00297     trans_op->ibs_op_phys_addr_low     = pop_buffer_value(trans);
00298     trans_op->ibs_op_phys_addr_high    = pop_buffer_value(trans);
00299 
00300     get_ibs_op_bta_sample(trans, trans_op);
00301 
00302     verbprintf(vsamples,
00303        "IBS_OP_X CPU:%ld PID:%d RIP:%lx D1HI:%x D1LO:%x D2LO:%x D3HI:%x D3LO:%x L_LO:%x P_LO:%x\n",
00304            trans->cpu,
00305            trans->tgid,
00306            trans_op->rip,
00307            trans_op->ibs_op_data1_high,
00308            trans_op->ibs_op_data1_low,
00309            trans_op->ibs_op_data2_low,
00310            trans_op->ibs_op_data3_high,
00311            trans_op->ibs_op_data3_low,
00312            trans_op->ibs_op_ldst_linaddr_low,
00313            trans_op->ibs_op_phys_addr_low);
00314 
00315     /* Overwrite the trans->pc with the more accurate trans_op->rip */
00316     trans->pc = trans_op->rip;
00317 
00318     opd_put_ibs_sample(trans);
00319 
00320     free(trans_op);
00321     free(trans->ext);
00322     trans->ext = NULL;
00323 }
00324 
00325 
00327 static unsigned long ibs_event_to_counter(unsigned long x)
00328 {
00329     unsigned long ret = ~0UL;
00330 
00331     if (IS_IBS_FETCH(x))
00332         ret = (x - IBS_FETCH_BASE);
00333     else if (IS_IBS_OP(x))
00334         ret = (x - IBS_OP_BASE + IBS_FETCH_MAX);
00335     else if (IS_IBS_OP_LS(x))
00336         ret = (x - IBS_OP_LS_BASE + IBS_OP_MAX + IBS_FETCH_MAX);
00337     else if (IS_IBS_OP_NB(x))
00338         ret = (x - IBS_OP_NB_BASE + IBS_OP_LS_MAX + IBS_OP_MAX + IBS_FETCH_MAX);
00339 
00340     return (ret != ~0UL) ? ret + OP_MAX_COUNTERS : ret;
00341 }
00342 
00343 
00344 void opd_log_ibs_event(unsigned int event,
00345     struct transient * trans)
00346 {
00347     ibs_derived_event_stats++;
00348     trans->event = event;
00349     sfile_log_sample_count(trans, 1);
00350 }
00351 
00352 
00353 void opd_log_ibs_count(unsigned int event,
00354             struct transient * trans,
00355             unsigned int count)
00356 {
00357     ibs_derived_event_stats++;
00358     trans->event = event;
00359     sfile_log_sample_count(trans, count);
00360 }
00361 
00362 
00363 static unsigned long get_ibs_vci_key(unsigned int event)
00364 {
00365     unsigned long key = ibs_event_to_counter(event);
00366     if (key == ~0UL || key < OP_MAX_COUNTERS)
00367         return ~0UL;
00368 
00369     key = key - OP_MAX_COUNTERS;
00370 
00371     return key;
00372 }
00373 
00374 
00375 static int ibs_parse_and_set_events(char * str)
00376 {
00377     char * tmp, * ptr, * tok1, * tok2 = NULL;
00378     int is_done = 0;
00379     struct op_event * event = NULL;
00380     op_cpu cpu_type = CPU_NO_GOOD;
00381     unsigned long key;
00382 
00383     if (!str)
00384         return -1;
00385 
00386     cpu_type = op_get_cpu_type();
00387     op_events(cpu_type);
00388 
00389     tmp = op_xstrndup(str, strlen(str));
00390     ptr = tmp;
00391 
00392     while (is_done != 1
00393         && (tok1 = strtok_r(ptr, ",", &tok2)) != NULL) {
00394 
00395         if ((ptr = strstr(tok1, ":")) != NULL) {
00396             *ptr = '\0';
00397             is_done = 1;
00398         }
00399 
00400         // Resove event number
00401         event = find_event_by_name(tok1, 0, 0);
00402         if (!event)
00403             return -1;
00404 
00405         // Grouping
00406         if (IS_IBS_FETCH(event->val)) {
00407             ibs_fetch_selected_flag |= 1 << IBS_FETCH_OFFSET(event->val);
00408         } else if (IS_IBS_OP(event->val)) {
00409             ibs_op_selected_flag |= 1 << IBS_OP_OFFSET(event->val);
00410         } else if (IS_IBS_OP_LS(event->val)) {
00411             ibs_op_ls_selected_flag |= 1 << IBS_OP_LS_OFFSET(event->val);
00412         } else if (IS_IBS_OP_NB(event->val)) {
00413             ibs_op_nb_selected_flag |= 1 << IBS_OP_NB_OFFSET(event->val);
00414         } else {
00415             return -1;
00416         }
00417 
00418         key = get_ibs_vci_key(event->val);
00419         if (key == ~0UL)
00420             return -1;
00421 
00422         ibs_vci_map[key] = ibs_selected_size;
00423 
00424         /* Initialize part of ibs_vc */
00425         ibs_vc[ibs_selected_size].name    = tok1;
00426         ibs_vc[ibs_selected_size].value   = event->val;
00427         ibs_vc[ibs_selected_size].counter = ibs_selected_size + OP_MAX_COUNTERS;
00428         ibs_vc[ibs_selected_size].kernel  = 1;
00429         ibs_vc[ibs_selected_size].user    = 1;
00430 
00431         ibs_selected_size++;
00432 
00433         ptr = NULL;
00434     }
00435 
00436     return 0;
00437 }
00438 
00439 
00440 static int ibs_parse_counts(char * str, unsigned long int * count)
00441 {
00442     char * tmp, * tok1, * tok2 = NULL, *end = NULL;
00443     if (!str)
00444         return -1;
00445 
00446     tmp = op_xstrndup(str, strlen(str));
00447     tok1 = strtok_r(tmp, ":", &tok2);
00448     *count = strtoul(tok1, &end, 10);
00449     if ((end && *end) || *count == 0
00450         || errno == EINVAL || errno == ERANGE) {
00451         fprintf(stderr,"Invalid count (%s)\n", str);
00452         return -1;
00453     }
00454 
00455     return 0;
00456 }
00457 
00458 
00459 static int ibs_parse_and_set_um_fetch(char const * str)
00460 {
00461     if (!str)
00462         return -1;
00463     return 0;
00464 }
00465 
00466 
00467 static int ibs_parse_and_set_um_op(char const * str, unsigned long int * ibs_op_um)
00468 {
00469     char * end = NULL;
00470     if (!str)
00471         return -1;
00472 
00473     *ibs_op_um = strtoul(str, &end, 16);
00474     if ((end && *end) || errno == EINVAL || errno == ERANGE) {
00475         fprintf(stderr,"Invalid unitmaks (%s)\n", str);
00476         return -1;
00477     }
00478     return 0;
00479 }
00480 
00481 
00482 static void check_cpuid_family_model_stepping()
00483 {
00484 #if defined(__i386__) || defined(__x86_64__) 
00485     unsigned eax = cpuid_signature();
00486 
00487     ibs_family   = cpu_family(eax);
00488     ibs_model    = cpu_model(eax);
00489     ibs_stepping = cpu_stepping(eax);
00490 #else
00491     ibs_family   = 0;
00492     ibs_model    = 0;
00493     ibs_stepping = 0;
00494 #endif
00495 }
00496 
00497 
00498 static int ibs_init(char const * argv)
00499 {
00500     char * tmp, * ptr, * tok1, * tok2 = NULL;
00501     unsigned int i = 0;
00502     unsigned long int ibs_fetch_count = 0;
00503     unsigned long int ibs_op_count = 0;
00504     unsigned long int ibs_op_um = 0;
00505 
00506     if (!argv)
00507         return -1;
00508 
00509     if (empty_line(argv) != 0)
00510         return -1;
00511 
00512     tmp = op_xstrndup(argv, strlen(argv));
00513     ptr = (char *) skip_ws(tmp);
00514 
00515     // "fetch:event1,event2,....:count:um|op:event1,event2,.....:count:um"
00516     tok1 = strtok_r(ptr, "|", &tok2);
00517 
00518     while (tok1 != NULL) {
00519 
00520         if (!strncmp("fetch:", tok1, strlen("fetch:"))) {
00521             // Get to event section
00522             tok1 = tok1 + strlen("fetch:");
00523             if (ibs_parse_and_set_events(tok1) == -1)
00524                 return -1;
00525 
00526             // Get to count section
00527             while (tok1) {
00528                 if (*tok1 == '\0')
00529                     return -1;
00530                 if (*tok1 != ':') {
00531                     tok1++;
00532                 } else {
00533                     tok1++;
00534                     break;
00535                 }
00536             }
00537 
00538             if (ibs_parse_counts(tok1, &ibs_fetch_count) == -1)
00539                 return -1;
00540 
00541             // Get to um section
00542             while (tok1) {
00543                 if (*tok1 == '\0')
00544                     return -1;
00545                 if (*tok1 != ':') {
00546                     tok1++;
00547                 } else {
00548                     tok1++;
00549                     break;
00550                 }
00551             }
00552 
00553             if (ibs_parse_and_set_um_fetch(tok1) == -1)
00554                 return -1;
00555 
00556         } else if (!strncmp("op:", tok1, strlen("op:"))) {
00557             // Get to event section
00558             tok1 = tok1 + strlen("op:");
00559             if (ibs_parse_and_set_events(tok1) == -1)
00560                 return -1;
00561 
00562             // Get to count section
00563             while (tok1) {
00564                 if (*tok1 == '\0')
00565                     return -1;
00566                 if (*tok1 != ':') {
00567                     tok1++;
00568                 } else {
00569                     tok1++;
00570                     break;
00571                 }
00572             }
00573 
00574             if (ibs_parse_counts(tok1, &ibs_op_count) == -1)
00575                 return -1;
00576 
00577             // Get to um section
00578             while (tok1) {
00579                 if (*tok1 == '\0')
00580                     return -1;
00581                 if (*tok1 != ':') {
00582                     tok1++;
00583                 } else {
00584                     tok1++;
00585                     break;
00586                 }
00587             }
00588 
00589             if (ibs_parse_and_set_um_op(tok1, &ibs_op_um))
00590                 return -1;
00591 
00592         } else
00593             return -1;
00594 
00595         tok1 = strtok_r(NULL, "|", &tok2);
00596     }
00597 
00598     /* Initialize ibs_vc */
00599     for (i = 0 ; i < ibs_selected_size ; i++)
00600     {
00601         if (IS_IBS_FETCH(ibs_vc[i].value)) {
00602             ibs_vc[i].count   = ibs_fetch_count;
00603             ibs_vc[i].um      = 0;
00604         } else {
00605             ibs_vc[i].count   = ibs_op_count;
00606             ibs_vc[i].um      = ibs_op_um;
00607         }
00608     }
00609 
00610     // Allow no event
00611     no_event_ok = 1;
00612 
00613     check_cpuid_family_model_stepping();
00614 
00615     get_ibs_bta_status();
00616 
00617     /* Create IBS memory access log */
00618     memaccess_log = NULL;
00619     if (ibs_op_um & 0x2) {
00620         char filename[PATH_MAX];
00621         char * log_file = "/samples/ibs_memaccess.log";
00622         size_t path_len = strlen(session_dir) + strlen(log_file);
00623         if (path_len < PATH_MAX) {
00624             strcpy(filename, session_dir);
00625             strcat(filename, log_file);
00626             memaccess_log = fopen(filename, "w");
00627         }
00628         if ( memaccess_log == NULL) {
00629             verbprintf(vext, "Warning: Cannot create ibs_memaccess.log\n");
00630             
00631         } else {
00632             fprintf (memaccess_log, "# IBS Memory Access Log\n\n");
00633             fprintf (memaccess_log, "# Format: app_cookie,cookie,cpu,tgid,tid,pc,branch-target-address,\n");
00634             fprintf (memaccess_log, "#         phy-hi:phy-low,lin-hi:lin-low,accese-type,latency\n\n");
00635         }
00636     }
00637 
00638     // Create IBS Branch Target Address (BTA) log   
00639     bta_log = NULL;
00640     if (ibs_bta_enabled) {
00641         char filename[PATH_MAX];
00642         char * log_file = "/samples/ibs_bta.log";
00643         size_t path_len = strlen(session_dir) + strlen(log_file);
00644         if (path_len < PATH_MAX) {
00645             strcpy(filename, session_dir);
00646             strcat(filename, log_file);
00647             bta_log = fopen(filename, "w");
00648         }
00649         if ( bta_log == NULL) {
00650             verbprintf(vext, "Warning: Cannot create ibs_bta.log\n");
00651         } else {
00652             fprintf (bta_log, "# IBS Memory Access Log\n\n");
00653             fprintf (bta_log, "# Format: app_cookie,cookie,cpu,tgid,tid,pc,branch-target-address\n\n");
00654         }
00655     }
00656 
00657     return 0;
00658 }
00659 
00660 
00661 static int ibs_deinit()
00662 {
00663     if (memaccess_log) {
00664         fclose (memaccess_log);
00665         memaccess_log = NULL;
00666     }
00667     
00668     if (bta_log) {
00669         fclose (bta_log);
00670         bta_log = NULL;
00671     }
00672     return 0;
00673 }
00674 
00675 
00676 static int ibs_print_stats()
00677 {
00678     printf("Nr. IBS Fetch samples     : %lu (%lu entries)\n", 
00679         ibs_fetch_sample_stats, (ibs_fetch_sample_stats * 7));
00680     printf("Nr. IBS Fetch incompletes : %lu\n", ibs_fetch_incomplete_stats);
00681     printf("Nr. IBS Op samples        : %lu (%lu entries)\n", 
00682         ibs_op_sample_stats, (ibs_op_sample_stats * 13));
00683     printf("Nr. IBS Op incompletes    : %lu\n", ibs_op_incomplete_stats);
00684     printf("Nr. IBS derived events    : %lu\n", ibs_derived_event_stats);
00685     return 0;
00686 }
00687 
00688 
00689 static int ibs_sfile_create(struct sfile * sf)
00690 {
00691     unsigned int i;
00692     sf->ext_files = xmalloc(ibs_selected_size * sizeof(odb_t));
00693     for (i = 0 ; i < ibs_selected_size ; ++i)
00694         odb_init(&sf->ext_files[i]);
00695 
00696     return 0;
00697 }
00698 
00699 
00700 static int ibs_sfile_dup (struct sfile * to, struct sfile * from)
00701 {
00702     unsigned int i;
00703     if (from->ext_files != NULL) {
00704         to->ext_files = xmalloc(ibs_selected_size * sizeof(odb_t));
00705         for (i = 0 ; i < ibs_selected_size ; ++i)
00706             odb_init(&to->ext_files[i]);
00707     } else {
00708         to->ext_files = NULL;
00709     }
00710     return 0;
00711 }
00712 
00713 static int ibs_sfile_close(struct sfile * sf)
00714 {
00715     unsigned int i;
00716     if (sf->ext_files != NULL) {
00717         for (i = 0; i < ibs_selected_size ; ++i)
00718             odb_close(&sf->ext_files[i]);
00719 
00720         free(sf->ext_files);
00721         sf->ext_files= NULL;
00722     }
00723     return 0;
00724 }
00725 
00726 static int ibs_sfile_sync(struct sfile * sf)
00727 {
00728     unsigned int i;
00729     if (sf->ext_files != NULL) {
00730         for (i = 0; i < ibs_selected_size ; ++i)
00731             odb_sync(&sf->ext_files[i]);
00732     }
00733     return 0;
00734 }
00735 
00736 static odb_t * ibs_sfile_get(struct transient const * trans, int is_cg)
00737 {
00738     struct sfile * sf = trans->current;
00739     struct sfile * last = trans->last;
00740     struct cg_entry * cg;
00741     struct list_head * pos;
00742     unsigned long hash;
00743     odb_t * file;
00744     unsigned long counter, ibs_vci, key;
00745 
00746     /* Note: "trans->event" for IBS is not the same as traditional
00747      * events.  Here, it has the actual event (0xfxxx), while the
00748      * traditional event has the event index.
00749      */
00750     key = get_ibs_vci_key(trans->event);
00751     if (key == ~0UL) {
00752         fprintf(stderr, "%s: Invalid IBS event %lu\n", __func__, trans->event);
00753         abort();
00754     }
00755     ibs_vci = ibs_vci_map[key];
00756     counter = ibs_vci + OP_MAX_COUNTERS;
00757 
00758     /* Creating IBS sfile if it not already exists */
00759     if (sf->ext_files == NULL)
00760         ibs_sfile_create(sf);
00761 
00762     file = &(sf->ext_files[ibs_vci]);
00763     if (!is_cg)
00764         goto open;
00765 
00766     hash = last->hashval & (CG_HASH_SIZE - 1);
00767 
00768     /* Need to look for the right 'to'. Since we're looking for
00769      * 'last', we use its hash.
00770      */
00771     list_for_each(pos, &sf->cg_hash[hash]) {
00772         cg = list_entry(pos, struct cg_entry, hash);
00773         if (sfile_equal(last, &cg->to)) {
00774             file = &(cg->to.ext_files[ibs_vci]);
00775             goto open;
00776         }
00777     }
00778 
00779     cg = xmalloc(sizeof(struct cg_entry));
00780     sfile_dup(&cg->to, last);
00781     list_add(&cg->hash, &sf->cg_hash[hash]);
00782     file = &(cg->to.ext_files[ibs_vci]);
00783 
00784 open:
00785     if (!odb_open_count(file))
00786         opd_open_sample_file(file, last, sf, counter, is_cg);
00787 
00788     /* Error is logged by opd_open_sample_file */
00789     if (!odb_open_count(file))
00790         return NULL;
00791 
00792     return file;
00793 }
00794 
00795 
00799 static struct opd_event * ibs_sfile_find_counter_event(unsigned long counter)
00800 {
00801     unsigned long ibs_vci;
00802 
00803     if (counter >= OP_MAX_COUNTERS + OP_MAX_IBS_COUNTERS
00804         || counter < OP_MAX_COUNTERS) {
00805         fprintf(stderr,"Error: find_ibs_counter_event : "
00806                 "invalid counter value %lu.\n", counter);
00807         abort();
00808     }
00809 
00810     ibs_vci = counter - OP_MAX_COUNTERS;
00811     return &ibs_vc[ibs_vci];
00812 }
00813 
00814 
00815 struct opd_ext_sfile_handlers ibs_sfile_handlers =
00816 {
00817     .create = &ibs_sfile_create,
00818     .dup    = &ibs_sfile_dup,
00819     .close  = &ibs_sfile_close,
00820     .sync   = &ibs_sfile_sync,
00821     .get    = &ibs_sfile_get,
00822     .find_counter_event = &ibs_sfile_find_counter_event
00823 };
00824 
00825 
00826 struct opd_ext_handlers ibs_handlers =
00827 {
00828     .ext_init        = &ibs_init,
00829     .ext_deinit      = &ibs_deinit,
00830     .ext_print_stats = &ibs_print_stats,
00831     .ext_sfile       = &ibs_sfile_handlers
00832 };

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1