Skip to content

Parallel Libtrace HOWTO: Result Callback

Shane Alcock edited this page Sep 21, 2015 · 10 revisions

The result callback is invoked for each result that reaches the reporter thread. In our example, this should collate all of the results together by updating the tally that is kept in our thread local storage.

static void per_result(libtrace_t *trace, libtrace_thread_t *sender,
        void *global, void *tls, libtrace_result_t *result) {

    struct udpresult *u;
    uint64_t key;
    struct udptally *tally;

    /* We only want to handle results containing our user-defined
     * structure. Check result->type to see what type of result this is.
     */
    if (result->type != RESULT_USER)
        return;

    /* The key is the same as the key value that was passed into 
     * trace_publish_result() when the processing thread published this
     * result. For now, our key will always be zero.
     */
    key = result->key;

    /* result->value is a libtrace_generic_t that was passed into
     * trace_publish_result() when the processing thread published this
     * result. In our case, we know that it is a pointer to a struct
     * udpresult so we can cast it to the right type.
     */
    u = (struct udpresult *)result->value.ptr;

    /* Grab our tally out of thread local storage and update it based on
     * this new result.
     */
    tally = (struct udptally *)tls;
    tally->packets += u->packets;
    tally->payload += u->payload;
    tally->lastkey = key;

    /* Remember that 'u' was malloced by the processing thread, so make sure
     * we free it here.
     */
    free(u);
}

This callback function introduces a new type libtrace_result_t, which contains the three parameters that were passed into trace_publish_result() to describe the result: the key, the value (as a libtrace_generic_t) and the result type. In this example, we only really care about the value but there are cases where the key and result type might be important as well, so I've included some basic code to demonstrate how these can be extracted from the result.

We can now update our tally, but we still need a method to write out our final results. We can write a stopping callback to the reporter to do this, as this will be called just before the reporter thread exits. No more results will be received by the reporter at this point, so we can safely assume our tally is final.

Here's our stopping callback:

static void stop_reporter(libtrace_t *trace, libtrace_thread_t *thread, 
        void *global, void *tls) {
    
    struct udpresult *tally;
    double avgsize = 0.0;

    /* Get our final tally from the thread local storage */
    tally = (struct udpresult *)tls;

    /* Calculate and output our final result! */
    if (tally->packets != 0)
        avgsize = tally->payload / (double)tally->packets;
    printf("Average UDP payload size is %.2f bytes\n", avgsize);
    
    /* Don't forget to free the thread local storage */
    free(tally);
}

We've now got all the callbacks we need to make our program work properly, so let's look at how to register our callbacks with libtrace.

Clone this wiki locally