Getting Core Utilization/Usage Information on XMOS Topic is solved

Technical questions regarding the XTC tools and programming with XMOS.
mozcelikors
Experienced Member
Posts: 75
Joined: Sat May 07, 2016 11:47 am

Getting Core Utilization/Usage Information on XMOS

Post by mozcelikors »

Hello guys,

In my application I need the core load info for each core, is getting that information (and further sending it over some protocol) possible real-time?

NOTE: I'm using xCORE-200 Explorer kit.

Thanks for the information in advance,
Cheers.
View Solution
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am

Post by mon2 »

peter
XCore Addict
Posts: 230
Joined: Wed Mar 10, 2010 12:46 pm

Post by peter »

There is a better way to do this which gives you the activity levels of cores. In the following code the monitorCores() task prints at a rate defined by the PRINT_MS define and polls at the rate controlled by the PRINT_MS define.

The code has a sample load task which you can specify how many milliseconds to run busy and how many to run idle. The top-level creates a few of these cores on the two tiles.

Code: Select all

#include <platform.h>
#include <xs1.h>
#include <stdio.h>
#include "debug_print.h"

#define ONE_MS_TICKS 100000
#define POLLING_MS (1 * ONE_MS_TICKS)
#define PRINT_MS (1000 * ONE_MS_TICKS)

[[combinable]]
void monitorCores()
{
  short int t;
  timer poll_tmr, print_tmr;
  int poll_time, print_time;
  poll_tmr :> poll_time;

  print_time = poll_time + PRINT_MS;

  int core_busy[8];
  int core_idle[8];
  for (t = 0; t <= 7; t++) {
    core_busy[t] = 0;
    core_idle[t] = 0;
  }

  int tile_id = get_local_tile_id();

  while(1)
  {
    select {
      case print_tmr when timerafter(print_time) :> void:
        debug_printf("tile[%x]: %d/%d %d/%d %d/%d %d/%d %d/%d %d/%d %d/%d %d/%d\n",
            tile_id,
            core_busy[0], core_idle[0],
            core_busy[1], core_idle[1],
            core_busy[2], core_idle[2],
            core_busy[3], core_idle[3],
            core_busy[4], core_idle[4],
            core_busy[5], core_idle[5],
            core_busy[6], core_idle[6],
            core_busy[7], core_idle[7]);

        for (t = 0; t <= 7; t++) {
          core_busy[t] = 0;
          core_idle[t] = 0;
        }
        print_time += PRINT_MS;
        break;

      case poll_tmr when timerafter(poll_time) :> void:
        for (t = 0; t <= 7; t++) {

          // Read the processor state
          int ps_value = getps(0x100*t+4);
          const int in_use = (ps_value & 0x1);

          if (in_use) {

            // Read the status register
            unsigned int sr_value;
            read_pswitch_reg(tile_id, XS1_PSWITCH_T0_SR_NUM+t, sr_value);
            const int waiting = (sr_value >> 6) & 0x1;

            if (waiting) {
              core_idle[t] += 1;
            } else {
              core_busy[t] += 1;
            }
          }
        }
        poll_time += POLLING_MS;
        break;
    }
  }
}

void load(int busy_ms, int idle_ms) {
  timer tmr;
  int time;
  tmr :> time;
  while (1) {
    // Busy time
    time += busy_ms * ONE_MS_TICKS;

    int busy = 1;
    while (busy) {
      select {
        case tmr when timerafter(time) :> void:
          busy = 0;
          break;
        default:
          break;
      }
    }

    // Idle time
    time += idle_ms * ONE_MS_TICKS;
    tmr when timerafter(time) :> void;
  }
}

int main()
{
  par {
    on tile[0] : monitorCores();
    on tile[0] : load(0, 100);
    on tile[0] : load(5, 95);
    on tile[0] : load(50, 50);

    on tile[1] : monitorCores();
    on tile[1] : load(50, 50);
    on tile[1] : load(10, 90);
    on tile[1] : load(1, 99);
  }
  return 0;
}
I used lib_logging because it is light-weight, so you'll need to include the following config.xscope:

Code: Select all

<xSCOPEconfig enabled="true" ioMode="basic">
</xSCOPEconfig>
When I run it it now prints something like:

Code: Select all

tile[8002]: 500/500 1000/0 950/50 1000/0 0/1000 0/1000 0/1000 0/1000
tile[8003]: 990/10 500/500 900/100 1000/0 0/1000 0/1000 0/1000 0/1000
tile[8002]: 500/500 1000/0 950/50 1000/0 0/1000 0/1000 0/1000 0/1000
tile[8003]: 990/10 500/500 900/100 1000/0 0/1000 0/1000 0/1000 0/1000
tile[8002]: 500/500 1000/0 950/50 1000/0 0/1000 0/1000 0/1000 0/1000
tile[8003]: 990/10 500/500 900/100 1000/0 0/1000 0/1000 0/1000 0/1000
tile[8002]: 500/500 1000/0 950/50 1000/0 0/1000 0/1000 0/1000 0/1000
which show the idle/busy counts for each core.

Hope that helps,

Peter
Last edited by peter on Mon Nov 07, 2016 12:55 pm, edited 1 time in total.
Reason: Fixed the code to correct busy/idle.
mozcelikors
Experienced Member
Posts: 75
Joined: Sat May 07, 2016 11:47 am

Post by mozcelikors »

Hello,

Thanks for the reply, looks like its gonna work.

Could you please check if I correctly transferred it to core utilization percentage. Thanks.

Note: Its either around 100% 99% or 0%. It doesnt feel correct :)

Code: Select all

[[combinable]]
void monitorCores(client core_stats_if core_stats_interface)
{
  short int t;
  timer poll_tmr, print_tmr;
  int poll_time, print_time;
  poll_tmr :> poll_time;

  print_time = poll_time + PRINT_MS;

  float core_busy[8];
  float core_idle[8];
  short int core_usage[8];

  for (t = 0; t <= 7; t++) {
    core_busy[t] = 0;
    core_idle[t] = 0;
  }

  int tile_id = get_local_tile_id();

  while(1)
  {
    select {
      case print_tmr when timerafter(print_time) :> void:
        for (t = 0; t <= 7; t++) {
            core_usage[t] = ((float)(core_busy[t] / (core_busy[t] + core_idle[t])))*100;
        }
        core_stats_interface.ShareCoreUsage (core_usage[0],
                                             core_usage[1],
                                             core_usage[2],
                                             core_usage[3],
                                             core_usage[4],
                                             core_usage[5],
                                             core_usage[6],
                                             core_usage[7]);
        /*printf("%d %d %d %d %d %d %d %d\n",core_usage[0],
                                        core_usage[1],
                                        core_usage[2],
                                        core_usage[3],
                                        core_usage[4],
                                        core_usage[5],
                                        core_usage[6],
                                        core_usage[7]);*/

        for (t = 0; t <= 7; t++) {
          core_busy[t] = 0;
          core_idle[t] = 0;
        }
        print_time += PRINT_MS;
        break;

      case poll_tmr when timerafter(poll_time) :> void:
        for (t = 0; t <= 7; t++) {
          // Read the processor state
          int ps_value = getps(0x100*t+4);

          // Read the status register
          unsigned int sr_value;
          read_pswitch_reg(tile_id, XS1_PSWITCH_T0_SR_NUM+t, sr_value);

          const int in_use = (ps_value & 0x1);
          const int waiting = (sr_value >> 6) & 0x1;
          if (in_use && waiting) {
            core_busy[t] += 1;
          } else {
            core_idle[t] += 1;
          }
        }
        poll_time += POLLING_MS;
        break;
    }
  }
}
peter
XCore Addict
Posts: 230
Joined: Wed Mar 10, 2010 12:46 pm

Post by peter »

Please note that I made a mistake in my original post which I corrected, so it should be:

Code: Select all

         if (in_use) {
            if (waiting) {
              core_idle[t] += 1;
            } else {
              core_busy[t] += 1;
            }
          }
Though this code doesn't count either if the core is not active.

Note that the xCORE doesn't have a floating point unit, so using float will result in slow code. I would recommend you use int instead and simply do:

Code: Select all

        for (t = 0; t <= 7; t++) {
            if (core_idle[t] + core_busy[t]) {
              core_usage[t] = (100 * core_busy[t]) / (core_busy[t] + core_idle[t]);
            } else {
              core_usage[t] = 0;
            }
        }
Just note that the one core that is running this will always look idle because it is always waiting when it reads the status register.

Peter
mozcelikors
Experienced Member
Posts: 75
Joined: Sat May 07, 2016 11:47 am

Post by mozcelikors »

Thanks for the kind helps. That should work.