Logging

Logging is available on DPU by using any of these functions:

  • void printf(const char *format, ...) writes a formatted string to the stdout buffer

  • void puts(const char *str) writes a simple string to the stdout buffer, with an added \n at the end.

  • void putchar(int x) writes a character to the stdout buffer

To use them, do not forget to include the stdio header (#include <stdio.h>).

Examples

Logging from dpu-lldb

Example

The next example illustrates how logging works. The DPU is going to perform some operations and will give some information at different points in its execution.

Next is the code achieving this task (in printf_example.c):

#include <stdio.h>

int main() {
  int i;
  for (i = 0; i < 32; i++) {
    printf("hello %02d=0x%02x times\n", i, i);
  }
  return 0;
}

The code is built to be executed by a single tasklet:

dpu-upmem-dpurte-clang printf_example.c -o printf_example

To validate that everything works, let’s launch the program with dpu-lldb:

file printf_example
process launch
exit

The displayed traces:

hello 00=0x00 times
hello 01=0x01 times
hello 02=0x02 times
hello 03=0x03 times
hello 04=0x04 times
hello 05=0x05 times
hello 06=0x06 times
hello 07=0x07 times
hello 08=0x08 times
hello 09=0x09 times
hello 10=0x0a times
hello 11=0x0b times
hello 12=0x0c times
hello 13=0x0d times
hello 14=0x0e times
hello 15=0x0f times
hello 16=0x10 times
hello 17=0x11 times
hello 18=0x12 times
hello 19=0x13 times
hello 20=0x14 times
hello 21=0x15 times
hello 22=0x16 times
hello 23=0x17 times
hello 24=0x18 times
hello 25=0x19 times
hello 26=0x1a times
hello 27=0x1b times
hello 28=0x1c times
hello 29=0x1d times
hello 30=0x1e times
hello 31=0x1f times

Logging from Host

It is also possible to log the DPU program execution from the Host API. But contrary to the execution with dpu-lldb the log will not be printed in the console during the execution.

The C Host Library provides a function to print the log after the execution of the DPU into a FILE * (stdout for example):

  • dpu_log_read(struct dpu_set_t set, FILE *stream)

However, only a set obtained from DPU_FOREACH can be used by this function. Trying to obtain the log from a set of multiple DPUs will result in the function returning DPU_ERR_INVALID_DPU_SET.

In C++, Java and Python, the Host library provides a log method which writes to an input stream the messages logged during the DPUs execution.

In the next example, a host application displays the log produced by a DPU program:

#include "dpu.h"
#include <stdio.h>
#include <assert.h>

#ifndef DPU_BINARY
#define DPU_BINARY "./printf_example"
#endif

int main() {
  struct dpu_set_t set, dpu;

  DPU_ASSERT(dpu_alloc(1, NULL, &set));
  printf("DPU allocated\n");
  DPU_ASSERT(dpu_load(set, DPU_BINARY, NULL));
  DPU_ASSERT(dpu_launch(set, DPU_SYNCHRONOUS));

  printf("printing log for dpu:\n");
  DPU_FOREACH(set, dpu) {
    DPU_ASSERT(dpu_log_read(dpu, stdout));
  }

  DPU_ASSERT(dpu_free(set));
  return 0;
}

Compile the program with gcc, for example:

gcc --std=c99 -o printf_example_host printf_example_host.c `dpu-pkg-config --libs --cflags dpu`

An execution of the host program produces the following output:

DPU allocated
printing log for dpu:
=== DPU#0x0 ===
hello 00=0x00 times
hello 01=0x01 times
hello 02=0x02 times
hello 03=0x03 times
hello 04=0x04 times
hello 05=0x05 times
hello 06=0x06 times
hello 07=0x07 times
hello 08=0x08 times
hello 09=0x09 times
hello 10=0x0a times
hello 11=0x0b times
hello 12=0x0c times
hello 13=0x0d times
hello 14=0x0e times
hello 15=0x0f times
hello 16=0x10 times
hello 17=0x11 times
hello 18=0x12 times
hello 19=0x13 times
hello 20=0x14 times
hello 21=0x15 times
hello 22=0x16 times
hello 23=0x17 times
hello 24=0x18 times
hello 25=0x19 times
hello 26=0x1a times
hello 27=0x1b times
hello 28=0x1c times
hello 29=0x1d times
hello 30=0x1e times
hello 31=0x1f times

Limitations

These functions write the messages and the value(s) in a circular buffer in the MRAM, using the specified representation for the value(s).

If an overflow occurs, i.e. if the number of bytes written is greater than the buffer size, the DPU will fault with the fault id 5.

The circular buffer allows dpu-lldb to always print the messages as long as they do not overflow, but with the Host Library, the behavior is not the same. If the full log of the application is bigger than the buffer size, the call to dpu_log_read will return DPU_ERR_LOG_BUFFER_TOO_SMALL.

The buffer size can be changed by using the macro STDOUT_BUFFER_INIT(size). size will determine the size of the stdout buffer in bytes, and it must be a strictly positive multiple of 8.