示例#1
0
/* Go through the activities, computing the start and elapsed time. */
static void
analyze_timeline (void)
{
  struct activity *activity;
  size_t i, j;
  int64_t delta_ns;

  for (j = 0; j < nr_activities; ++j) {
    activity = &activities[j];

    activity->t = 0;
    activity->mean = 0;
    for (i = 0; i < NR_TEST_PASSES; ++i) {
      delta_ns =
        timespec_diff (&pass_data[i].events[0].t,
                       &pass_data[i].events[activity->start_event[i]].t);
      activity->t += delta_ns;

      delta_ns =
        timespec_diff (&pass_data[i].events[activity->start_event[i]].t,
                       &pass_data[i].events[activity->end_event[i]].t);
      activity->mean += delta_ns;
    }

    /* Divide through to get real start time and mean of each activity. */
    activity->t /= NR_TEST_PASSES;
    activity->mean /= NR_TEST_PASSES;

    /* Calculate the end time of this activity.  It's convenient when
     * drawing the timeline for one activity to finish just before the
     * next activity starts, rather than having them end and start at
     * the same time, hence ``- 1'' here.
     */
    activity->end_t = activity->t + activity->mean - 1;

    /* The above only calculated mean.  Now we are able to
     * calculate from the mean the variance and the standard
     * deviation.
     */
    activity->variance = 0;
    for (i = 0; i < NR_TEST_PASSES; ++i) {
      delta_ns =
        timespec_diff (&pass_data[i].events[activity->start_event[i]].t,
                       &pass_data[i].events[activity->end_event[i]].t);
      activity->variance += pow (delta_ns - activity->mean, 2);
    }
    activity->variance /= NR_TEST_PASSES;

    activity->sd = sqrt (activity->variance);
  }

  /* Get the total mean elapsed time from the special "run" activity. */
  activity = find_activity ("run");
  for (j = 0; j < nr_activities; ++j) {
    activities[j].percent = 100.0 * activities[j].mean / activity->mean;

    activities[j].warning =
      !(activities[j].flags & LONG_ACTIVITY) &&
      activities[j].percent >= WARNING_THRESHOLD;
  }

  /* Sort the activities by start time. */
  qsort (activities, nr_activities, sizeof (struct activity),
         compare_activities_by_t);
}
/* Handling of initcall is so peculiar that we hide it in a separate
 * function from the rest.
 */
static void
construct_initcall_timeline (void)
{
  size_t i, j, k;
  struct pass_data *data;
  struct activity *activity;

  for (i = 0; i < NR_TEST_PASSES; ++i) {
    data = &pass_data[i];

    /* Each kernel initcall is bracketed by:
     *
     * calling  ehci_hcd_init+0x0/0xc1 @ 1"
     * initcall ehci_hcd_init+0x0/0xc1 returned 0 after 420 usecs"
     *
     * For initcall functions in modules:
     *
     * calling  virtio_mmio_init+0x0/0x1000 [virtio_mmio] @ 1"
     * initcall virtio_mmio_init+0x0/0x1000 [virtio_mmio] returned 0 after 14 usecs"
     *
     * Initcall functions can be nested, and do not have unique names.
     */
    for (j = 0; j < data->nr_events; ++j) {
      int vec[30], r;
      const char *message = data->events[j].message;

      if (data->events[j].source == GUESTFS_EVENT_APPLIANCE &&
          ((r = pcre_exec (re_initcall_calling_module, NULL,
                           message, strlen (message),
                           0, 0, vec, sizeof vec / sizeof vec[0])) >= 1 ||
           (r = pcre_exec (re_initcall_calling, NULL,
                           message, strlen (message),
                           0, 0, vec, sizeof vec / sizeof vec[0])) >= 1)) {

        CLEANUP_FREE char *fn_name = NULL, *module_name = NULL;
        if (r >= 2) /* because pcre_exec returns 1 + number of captures */
          fn_name = strndup (message + vec[2], vec[3]-vec[2]);
        if (r >= 3)
          module_name = strndup (message + vec[4], vec[5]-vec[4]);

        CLEANUP_FREE char *fullname;
        if (asprintf (&fullname, "%s.%s",
                      module_name ? module_name : "kernel", fn_name) == -1)
          error (EXIT_FAILURE, errno, "asprintf");

        CLEANUP_FREE char *initcall_match;
        if (asprintf (&initcall_match, "initcall %s", fn_name) == -1)
          error (EXIT_FAILURE, errno, "asprintf");

        /* Get a unique name for this activity.  Unfortunately
         * kernel initcall function names are not unique!
         */
        CLEANUP_FREE char *activity_name;
        if (asprintf (&activity_name, "initcall %s", fullname) == -1)
          error (EXIT_FAILURE, errno, "asprintf");

        if (i == 0) {
          int n = 1;
          while (activity_exists (activity_name)) {
            free (activity_name);
            if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1)
              error (EXIT_FAILURE, errno, "asprintf");
            n++;
          }
        }
        else {
          int n = 1;
          while (!activity_exists_with_no_data (activity_name, i)) {
            free (activity_name);
            if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1)
              error (EXIT_FAILURE, errno, "asprintf");
            n++;
          }
        }

        /* Find the matching end event.  It might be some time later,
         * since it appears initcalls can be nested.
         */
        for (k = j+1; k < data->nr_events; ++k) {
          if (data->events[k].source == GUESTFS_EVENT_APPLIANCE &&
              strstr (data->events[k].message, initcall_match)) {
            if (i == 0)
              activity = add_activity (activity_name, 0);
            else
              activity = find_activity (activity_name);
            activity->start_event[i] = j;
            activity->end_event[i] = k;
            break;
          }
        }
      }
    }
  }
}