+
+/****************************************************************************
+* anomaly_statistics_init
+****************************************************************************/
+
+static int anomaly_statistics_init (void)
+{
+ elog_event_t *eep;
+ u32 data;
+ event_t *ep;
+ pid_data_t *pid;
+ int i;
+ f64 fdata;
+
+ /* Gather summary statistics... */
+ ep = g_events;
+
+ vec_reset_length (s_v1->means);
+ vec_reset_length (s_v1->matches);
+ vec_reset_length (s_v1->variances);
+ vec_reset_length (s_v1->two_stddevs);
+ vec_reset_length (s_v1->mins);
+ vec_reset_length (s_v1->maxes);
+
+ for (i = 0; i < g_nevents; i++) {
+ if (ep->code != s_anomalycode) {
+ ep++;
+ continue;
+ }
+ pid = ep->pid;
+ vec_validate_init_empty (s_v1->matches, pid->pid_index, 0);
+ vec_validate_init_empty (s_v1->means, pid->pid_index, 0.0);
+ vec_validate_init_empty (s_v1->mins, pid->pid_index, 0.0);
+ vec_validate_init_empty (s_v1->maxes, pid->pid_index, 0.0);
+ eep = get_clib_event (ep->datum);
+ data = clib_mem_unaligned (eep->data, u32);
+ fdata = data;
+ s_v1->means[pid->pid_index] += fdata;
+ s_v1->matches[pid->pid_index] += 1;
+ /* First data point? set min, max */
+ if (PREDICT_FALSE(s_v1->matches[pid->pid_index] == 1)) {
+ s_v1->mins[pid->pid_index] = fdata;
+ s_v1->maxes[pid->pid_index] = fdata;
+ } else {
+ s_v1->mins[pid->pid_index] = (fdata < s_v1->mins[pid->pid_index]) ?
+ fdata : s_v1->mins[pid->pid_index];
+ s_v1->maxes[pid->pid_index] =
+ (fdata > s_v1->maxes[pid->pid_index]) ?
+ fdata : s_v1->maxes[pid->pid_index];
+ }
+ ep++;
+ }
+ if (vec_len (s_v1->matches) == 0)
+ return -1;
+
+ /* Compute s_v1->means */
+ for (i = 0; i < vec_len (s_v1->means); i++)
+ s_v1->means[i] = s_v1->matches[i]
+ ? (s_v1->means[i] / (f64) s_v1->matches[i]) : 0.0;
+
+ /* Compute s_v1->variances */
+ ep = g_events;
+ for (i = 0; i < g_nevents; i++) {
+ if (ep->code != s_anomalycode) {
+ ep++;
+ continue;
+ }
+ pid = ep->pid;
+ vec_validate_init_empty (s_v1->variances, pid->pid_index, 0);
+ eep = get_clib_event (ep->datum);
+ data = clib_mem_unaligned (eep->data, u32);
+ fdata = data;
+ s_v1->variances[pid->pid_index] +=
+ (fdata - s_v1->means[pid->pid_index])
+ * (fdata - s_v1->means[pid->pid_index]);
+ ep++;
+ }
+
+ /* Normalize variances */
+ for (i = 0; i < vec_len (s_v1->variances); i++)
+ s_v1->variances[i] = s_v1->matches[i]
+ ? (s_v1->variances[i] / (f64) s_v1->matches[i]) : 0.0;
+
+ /* Compute the anomaly threshold, by default 2.5*stddev */
+ for (i = 0; i < vec_len (s_v1->variances); i++)
+ vec_add1 (s_v1->two_stddevs,
+ s_v1->anomaly_threshold_stddevs * sqrt(s_v1->variances[i]));
+ return 0;
+}
+
+/****************************************************************************
+* anomaly_search_internal
+* This routine searches forward from s_srchindex, looking for s_srchcode;
+* wraps at the end of the buffer.
+****************************************************************************/
+
+boolean anomaly_search_internal (void)
+{
+ elog_event_t *eep;
+ u32 data;
+ event_t *ep;
+ pid_data_t *pid;
+ int i;
+ int index;
+ int pid_index;
+ boolean full_redisplay = FALSE;
+ ulonglong current_width;
+ char tmpbuf [64];
+ f64 fdata;
+
+ if (vec_len (s_v1->matches) == 0)
+ anomaly_statistics_init();
+
+ ep = (g_events + s_srchindex);
+ ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
+
+ /*
+ * If the user rearranged the screen, start from the minimum
+ * visible time
+ */
+ if (ep->time < s_v1->minvistime)
+ s_srchindex = find_event_index (s_v1->minvistime);
+
+ for (i = 1; i <= g_nevents; i++) {
+ index = (i + s_srchindex) % g_nevents;
+
+ ep = (g_events + index);
+ if (ep->code != s_anomalycode)
+ continue;
+ pid = ep->pid;
+
+ eep = get_clib_event (ep->datum);
+ data = clib_mem_unaligned (eep->data, u32);
+ fdata = data;
+
+ /*
+ * Found an anomaly? Define an anomaly as a datum
+ * greater than 2*stddev above average.
+ */
+ if ((fdata - s_v1->means[pid->pid_index]) >
+ s_v1->two_stddevs[pid->pid_index]) {
+ u8 *s;
+
+ s = format (0, "%.1f*stddev {min,max,mean,threshold}: ",
+ s_v1->anomaly_threshold_stddevs);
+
+ for (i = 0; i < vec_len (s_v1->means); i++) {
+ if (s_v1->matches[i] > 0)
+ s = format (s, "{%.0f, %.0f, %.0f, %.0f} ",
+ s_v1->mins[i], s_v1->maxes[i],
+ s_v1->means[i],
+ s_v1->means[i]+s_v1->two_stddevs[i]);
+ else
+ s = format (s, "{no match} ");
+ }
+
+ message_line ((char *)s);
+ vec_free (s);
+
+ s_srchindex = index;
+ pid_index = ep->pid->pid_index;
+
+ /* Need a vertical scroll? */
+ if ((pid_index < s_v1->first_pid_index) ||
+ (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
+ if (pid_index > (g_npids - s_v1->npids))
+ pid_index = (g_npids - s_v1->npids);
+ s_v1->first_pid_index = pid_index;
+ GTK_ADJUSTMENT(s_view1_vsadj)->value =
+ (gdouble)s_v1->first_pid_index;
+ gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
+ full_redisplay = TRUE;
+ }
+
+ /* Need a horizontal scroll? */
+ if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
+ current_width = (s_v1->maxvistime - s_v1->minvistime);
+ if (ep->time < ((current_width+1) / 2)) {
+ s_v1->minvistime = 0ll;
+ s_v1->maxvistime = current_width;
+ } else {
+ s_v1->minvistime = ep->time - ((current_width+1)/2);
+ s_v1->maxvistime = ep->time + ((current_width+1)/2);
+ }
+ recompute_hscrollbar();
+ full_redisplay = TRUE;
+ }
+ ep->flags |= EVENT_FLAG_SEARCHRSLT;
+ full_redisplay = TRUE;
+
+ if (full_redisplay)
+ view1_display_when_idle();
+
+ return(TRUE);
+ }
+ }
+ snprintf (tmpbuf, sizeof(tmpbuf),
+ "Search for an anomalous event %ld failed...\n",
+ s_anomalycode);
+ message_line(tmpbuf);
+ s_srchfail_up = TRUE;
+ return(TRUE);
+}
+
+/****************************************************************************
+* anomaly_search_callback
+****************************************************************************/
+
+boolean anomaly_search_callback (char *s)
+{
+ ulong new_anomalycode;
+
+ /* No events yet? Act like the search worked, to avoid a loop */
+ if (g_nevents == 0)
+ return(TRUE);
+
+ new_anomalycode = atol(s);
+
+ if (new_anomalycode == 0)
+ return(FALSE);
+
+ if (new_anomalycode != s_anomalycode ||
+ vec_len (s_v1->matches) == 0) {
+ s_anomalycode = new_anomalycode;
+ if (anomaly_statistics_init()) {
+ u8 *s;
+
+ s = format (0, "Search for an anomalous event %ld failed...\n",
+ s_anomalycode);
+ message_line ((char *) s);
+ vec_free (s);
+ return (TRUE);
+ }
+ }
+ return(anomaly_search_internal());
+}
+
+/****************************************************************************
+* anomaly_threshold_callback
+****************************************************************************/
+
+boolean anomaly_threshold_callback (char *s)
+{
+ f64 new_threshold;
+
+ /* No events yet? Act like the search worked, to avoid a loop */
+ if (g_nevents == 0)
+ return(TRUE);
+
+ new_threshold = atof (s);
+
+ if (new_threshold == 0.0 || new_threshold > 10.0)
+ return(FALSE);
+
+ s_v1->anomaly_threshold_stddevs = new_threshold;
+
+ vec_reset_length (s_v1->means);
+ vec_reset_length (s_v1->matches);
+ vec_reset_length (s_v1->variances);
+ vec_reset_length (s_v1->two_stddevs);
+ return (TRUE);
+}
+