📄 dl-profile.c
字号:
char buf[400]; _dl_error_printf ("%s: cannot open file: %s\n", filename, __strerror_r (errno, buf, sizeof buf)); return; } if (fstat64 (fd, &st) < 0 || !S_ISREG (st.st_mode)) { /* Not stat'able or not a regular file => don't use it. */ char buf[400]; int errnum = errno; __close (fd); _dl_error_printf ("%s: cannot stat file: %s\n", filename, __strerror_r (errnum, buf, sizeof buf)); return; } /* Test the size. If it does not match what we expect from the size values in the map MAP we don't use it and warn the user. */ if (st.st_size == 0) { /* We have to create the file. */ char buf[_dl_pagesize]; memset (buf, '\0', _dl_pagesize); if (__lseek (fd, expected_size & ~(_dl_pagesize - 1), SEEK_SET) == -1) { char buf[400]; int errnum; cannot_create: errnum = errno; __close (fd); _dl_error_printf ("%s: cannot create file: %s\n", filename, __strerror_r (errnum, buf, sizeof buf)); return; } if (TEMP_FAILURE_RETRY (__libc_write (fd, buf, (expected_size & (_dl_pagesize - 1)))) < 0) goto cannot_create; } else if (st.st_size != expected_size) { __close (fd); wrong_format: if (addr != NULL) __munmap ((void *) addr, expected_size); _dl_error_printf ("%s: file is no correct profile data file for `%s'\n", filename, _dl_profile); return; } addr = (struct gmon_hdr *) __mmap (NULL, expected_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FILE, fd, 0); if (addr == (struct gmon_hdr *) MAP_FAILED) { char buf[400]; int errnum = errno; __close (fd); _dl_error_printf ("%s: cannot map file: %s\n", filename, __strerror_r (errnum, buf, sizeof buf)); return; } /* We don't need the file desriptor anymore. */ __close (fd); /* Pointer to data after the header. */ hist = (char *) (addr + 1); kcount = (uint16_t *) ((char *) hist + sizeof (uint32_t) + sizeof (struct gmon_hist_hdr)); /* Compute pointer to array of the arc information. */ narcsp = (uint32_t *) ((char *) kcount + kcountsize + sizeof (uint32_t)); data = (struct here_cg_arc_record *) ((char *) narcsp + sizeof (uint32_t)); if (st.st_size == 0) { /* Create the signature. */ memcpy (addr, &gmon_hdr, sizeof (struct gmon_hdr)); *(uint32_t *) hist = GMON_TAG_TIME_HIST; memcpy (hist + sizeof (uint32_t), &hist_hdr, sizeof (struct gmon_hist_hdr)); narcsp[-1] = GMON_TAG_CG_ARC; } else { /* Test the signature in the file. */ if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0 || *(uint32_t *) hist != GMON_TAG_TIME_HIST || memcmp (hist + sizeof (uint32_t), &hist_hdr, sizeof (struct gmon_hist_hdr)) != 0 || narcsp[-1] != GMON_TAG_CG_ARC) goto wrong_format; } /* Allocate memory for the froms data and the pointer to the tos records. */ tos = (uint16_t *) calloc (tossize + fromssize, 1); if (tos == NULL) { __munmap ((void *) addr, expected_size); _dl_fatal_printf ("Out of memory while initializing profiler\n"); /* NOTREACHED */ } froms = (struct here_fromstruct *) ((char *) tos + tossize); fromidx = 0; /* Now we have to process all the arc count entries. BTW: it is not critical whether the *NARCSP value changes meanwhile. Before we enter a new entry in to toset we will check that everything is available in TOS. This happens in _dl_mcount. Loading the entries in reverse order should help to get the most frequently used entries at the front of the list. */ for (idx = narcs = MIN (*narcsp, fromlimit); idx > 0; ) { size_t to_index; size_t newfromidx; --idx; to_index = (data[idx].self_pc / (hashfraction * sizeof (*tos))); newfromidx = fromidx++; froms[newfromidx].here = &data[idx]; froms[newfromidx].link = tos[to_index]; tos[to_index] = newfromidx; } /* Setup counting data. */ if (kcountsize < highpc - lowpc) {#if 0 s_scale = ((double) kcountsize / (highpc - lowpc)) * SCALE_1_TO_1;#else size_t range = highpc - lowpc; size_t quot = range / kcountsize; if (quot >= SCALE_1_TO_1) s_scale = 1; else if (quot >= SCALE_1_TO_1 / 256) s_scale = SCALE_1_TO_1 / quot; else if (range > ULONG_MAX / 256) s_scale = (SCALE_1_TO_1 * 256) / (range / (kcountsize / 256)); else s_scale = (SCALE_1_TO_1 * 256) / ((range * 256) / kcountsize);#endif } else s_scale = SCALE_1_TO_1; /* Start the profiler. */ profil ((void *) kcount, kcountsize, lowpc, s_scale); /* Turn on profiling. */ running = 1;}void_dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc){ volatile uint16_t *topcindex; size_t i, fromindex; struct here_fromstruct *fromp; if (! running) return; /* Compute relative addresses. The shared object can be loaded at any address. The value of frompc could be anything. We cannot restrict it in any way, just set to a fixed value (0) in case it is outside the allowed range. These calls show up as calls from <external> in the gprof output. */ frompc -= lowpc; if (frompc >= textsize) frompc = 0; selfpc -= lowpc; if (selfpc >= textsize) goto done; /* Getting here we now have to find out whether the location was already used. If yes we are lucky and only have to increment a counter (this also has to be atomic). If the entry is new things are getting complicated... */ /* Avoid integer divide if possible. */ if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) i = selfpc >> log_hashfraction; else i = selfpc / (hashfraction * sizeof (*tos)); topcindex = &tos[i]; fromindex = *topcindex; if (fromindex == 0) goto check_new_or_add; fromp = &froms[fromindex]; /* We have to look through the chain of arcs whether there is already an entry for our arc. */ while (fromp->here->from_pc != frompc) { if (fromp->link != 0) do fromp = &froms[fromp->link]; while (fromp->link != 0 && fromp->here->from_pc != frompc); if (fromp->here->from_pc != frompc) { topcindex = &fromp->link; check_new_or_add: /* Our entry is not among the entries we read so far from the data file. Now see whether we have to update the list. */ while (narcs != *narcsp && narcs < fromlimit) { size_t to_index; size_t newfromidx; to_index = (data[narcs].self_pc / (hashfraction * sizeof (*tos))); newfromidx = exchange_and_add (&fromidx, 1) + 1; froms[newfromidx].here = &data[narcs]; froms[newfromidx].link = tos[to_index]; tos[to_index] = newfromidx; atomic_add (&narcs, 1); } /* If we still have no entry stop searching and insert. */ if (*topcindex == 0) { uint32_t newarc = exchange_and_add (narcsp, 1); /* In rare cases it could happen that all entries in FROMS are occupied. So we cannot count this anymore. */ if (newarc >= fromlimit) goto done; *topcindex = exchange_and_add (&fromidx, 1) + 1; fromp = &froms[*topcindex]; fromp->here = &data[newarc]; data[newarc].from_pc = frompc; data[newarc].self_pc = selfpc; data[newarc].count = 0; fromp->link = 0; atomic_add (&narcs, 1); break; } fromp = &froms[*topcindex]; } else /* Found in. */ break; } /* Increment the counter. */ atomic_add (&fromp->here->count, 1); done: ;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -