Getting more accurate core utilization in percentage inXMOS 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

Post by mozcelikors »

Any suggestions guys?


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

Post by mozcelikors »

Guys, I really need to find the core usage for every core in my application real-time.
The code is based on peter's code.
I'm making a 5-stage averaging in order to distinctly find the core usage values such as 0%,20%,40%,60%,80%,100% from the switching of values 0 and 100.

The code I'm using is following:

Code: Select all

[[combinable]]
void Task_MonitorCoresInATile(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;

      short int core_busy[8];
      short int 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();
      int cntr = 0;

      while(1)
      {
            select {
                  case print_tmr when timerafter(print_time) :> void:
                        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++) {
                                  if (core_idle[t] + core_busy[t] > 0) {
                                      core_usage[t] = core_usage[t] + (100 * core_busy[t]) / (core_busy[t] + core_idle[t]);

                                  } else {
                                      core_usage[t] = core_usage[t] + 0;
                                  }
                          }
                          cntr = cntr + 1;
                          if (cntr == 5)
                          {
                                  if (core_usage[0]>=0 && core_usage[0]<=500)
                                  {
                                      core_stats_interface.ShareCoreUsage (core_usage[0] /5,
                                                                         core_usage[1] /5,
                                                                         core_usage[2] /5,
                                                                         core_usage[3] /5,
                                                                         core_usage[4] /5,
                                                                         core_usage[5] /5,
                                                                         core_usage[6] /5,
                                                                         core_usage[7] /5);
                                      printf("tile[%x]: %d %d %d %d %d %d %d %d\n\n",tile_id, core_usage[0] /5,
                                                                        core_usage[1] /5,
                                                                        core_usage[2] /5,
                                                                        core_usage[3] /5,
                                                                        core_usage[4] /5,
                                                                        core_usage[5] /5,
                                                                        core_usage[6] /5,
                                                                        core_usage[7] /5);
                                      for (t = 0; t <= 7; t++) {
                                          core_usage[t] = 0;
                                      }
                                      cntr = 0;
                                  }
                                  else
                                  {
                                        for (t = 0; t <= 7; t++) {
                                            core_usage[t] = 0;
                                        }
                                        cntr = 0;
                                  }
                        }

                        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) {
                                      if (waiting) {
                                          core_idle[t] += 1;
                                      } else {
                                          core_busy[t] += 1;
                                      }
                              }

                        }
                        poll_time += POLLING_MS;
                        break;
            }
      }
}
Now, I think the code fails to find about finding core usage of distinct cores.

Please take a look at the examples below showing its strange behavior:

Code: Select all

Behavior examples:
EXAMPLE1
Tile 0:

Code: Select all

on tile[0].core[6]:              Task_ControlLightSystem (PortLightSystem_TH, PortLightSystem_ST, lightstate_interface);
on tile[0].core[5] :   Task_GetRemoteCommandsViaBluetooth(i_tx, i_rx, control_interface, steering_interface, i_cmd_from_ethernet_to_override, lightstate_interface);
on tile[0] : load(50,50);
on tile[0].core[7]:           Task_MonitorCoresInATile (core_stats_interface_tile0);
on tile[0]: xtcp(c_xtcp, ...);
on tile[0]: Task_EthernetAppTCPServer(c_xtcp[0], i_cmd_from_ethernet_to_override, core_stats_interface_tile0, core_stats_interface_tile1);
on tile[1].core[1]:           Task_MonitorCoresInATile (core_stats_interface_tile1);
Tile 1:

Code: Select all

on tile[1]: rgmii_ethernet_mac(i_eth_rx, NUM_ETH_CLIENTS, i_eth_tx, NUM_ETH_CLIENTS,
             null, null,
             c_rgmii_cfg, rgmii_ports,
             ETHERNET_DISABLE_SHAPER);
on tile[1].core[0]: rgmii_ethernet_mac_config(i_eth_cfg, NUM_CFG_CLIENTS, c_rgmii_cfg);
on tile[1].core[0]: ar8035_phy_driver(i_smi, i_eth_cfg[CFG_TO_PHY_DRIVER]);
on tile[1]: smi(i_smi, p_smi_mdio, p_smi_mdc);
Output:

Code: Select all

tile[8002]: 0 0 46 100 0 0 0 0
tile[8003]: 100 0 0 100 100 0 0 0
EXAMPLE2
If we just add the following to the above code Tile 0:

Code: Select all

on tile[0].core[4] :         Task_DriveTBLE02S_MotorController(PortMotorSpeedController, control_interface, sensors_interface);
 on tile[0].core[4] :         Task_SteeringServo_MotorController (PortSteeringServo, steering_interface);
Hence the code becomes:
Tile 0:

Code: Select all

on tile[0].core[6]:              Task_ControlLightSystem (PortLightSystem_TH, PortLightSystem_ST, lightstate_interface);
on tile[0].core[5] :   Task_GetRemoteCommandsViaBluetooth(i_tx, i_rx, control_interface, steering_interface, i_cmd_from_ethernet_to_override, lightstate_interface);
on tile[0] : load(50,50);
on tile[0].core[7]:           Task_MonitorCoresInATile (core_stats_interface_tile0);
on tile[0]: xtcp(c_xtcp, ...);
on tile[0]: Task_EthernetAppTCPServer(c_xtcp[0], i_cmd_from_ethernet_to_override, core_stats_interface_tile0, core_stats_interface_tile1);
on tile[1].core[1]:           Task_MonitorCoresInATile (core_stats_interface_tile1);
on tile[0].core[4] :         Task_DriveTBLE02S_MotorController(PortMotorSpeedController, control_interface, sensors_interface);
 on tile[0].core[4] :         Task_SteeringServo_MotorController (PortSteeringServo, steering_interface);
Tile 1:

Code: Select all

on tile[1]: rgmii_ethernet_mac(i_eth_rx, NUM_ETH_CLIENTS, i_eth_tx, NUM_ETH_CLIENTS,
             null, null,
             c_rgmii_cfg, rgmii_ports,
             ETHERNET_DISABLE_SHAPER);
on tile[1].core[0]: rgmii_ethernet_mac_config(i_eth_cfg, NUM_CFG_CLIENTS, c_rgmii_cfg);
on tile[1].core[0]: ar8035_phy_driver(i_smi, i_eth_cfg[CFG_TO_PHY_DRIVER]);
on tile[1]: smi(i_smi, p_smi_mdio, p_smi_mdc);
Output:

Code: Select all

tile[8002]: 0 0 0 0 47 100 0 0
tile[8003]: 100 0 0 100 100 0 0 0
EXAMPLE3
Adding the following to tile0 placement of EXAMPLE2:

Code: Select all

on tile[0] :         Task_MaintainI2CConnection(i2c_client_device_instances, 1, PortSCL, PortSDA, I2C_SPEED_KBITPERSEC);
on tile[0] :           Task_ReadSonarSensors(i2c_client_device_instances[0], sensors_interface);
Hence the code becomes:
Tile 0:

Code: Select all

on tile[0] :         Task_MaintainI2CConnection(i2c_client_device_instances, 1, PortSCL, PortSDA, I2C_SPEED_KBITPERSEC);
on tile[0] :           Task_ReadSonarSensors(i2c_client_device_instances[0], sensors_interface);
on tile[0].core[6]:              Task_ControlLightSystem (PortLightSystem_TH, PortLightSystem_ST, lightstate_interface);
on tile[0].core[5] :   Task_GetRemoteCommandsViaBluetooth(i_tx, i_rx, control_interface, steering_interface, i_cmd_from_ethernet_to_override, lightstate_interface);
on tile[0] : load(50,50);
on tile[0].core[7]:           Task_MonitorCoresInATile (core_stats_interface_tile0);
on tile[0]: xtcp(c_xtcp, ...);
on tile[0]: Task_EthernetAppTCPServer(c_xtcp[0], i_cmd_from_ethernet_to_override, core_stats_interface_tile0, core_stats_interface_tile1);
on tile[1].core[1]:           Task_MonitorCoresInATile (core_stats_interface_tile1);
on tile[0].core[4] :         Task_DriveTBLE02S_MotorController(PortMotorSpeedController, control_interface, sensors_interface);
 on tile[0].core[4] :         Task_SteeringServo_MotorController (PortSteeringServo, steering_interface);
Tile 1:

Code: Select all

on tile[1]: rgmii_ethernet_mac(i_eth_rx, NUM_ETH_CLIENTS, i_eth_tx, NUM_ETH_CLIENTS,
             null, null,
             c_rgmii_cfg, rgmii_ports,
             ETHERNET_DISABLE_SHAPER);
on tile[1].core[0]: rgmii_ethernet_mac_config(i_eth_cfg, NUM_CFG_CLIENTS, c_rgmii_cfg);
on tile[1].core[0]: ar8035_phy_driver(i_smi, i_eth_cfg[CFG_TO_PHY_DRIVER]);
on tile[1]: smi(i_smi, p_smi_mdio, p_smi_mdc);
Output:

Code: Select all

tile[8002]: 0 0 0 0 0 48 100 1

tile[8003]: 100 0 0 100 100 0 0 0
As you can see it, the output is really really weird to my understanding. I would like to see the core usage info for a distinct core if I placed a task on a distinct core, but it clearly does not work that way.
Any help is appreciated.
Gothmag
XCore Addict
Posts: 129
Joined: Wed May 11, 2016 3:50 pm

Post by Gothmag »

I didn't see much useful in your posted code to help figure it out. In an event driven processor you may have long periods of inactivity, and long periods of incredible activity. The one consistent thing is I saw 1 cores activity being near 50% and a load thread. So is that relatively accurate?

I'm pretty sure any printing will cause changes in timing and that might need to be considered. Could you potentially log that data using a core so that you know there are no prints causing timing issues? Also what are your time periods(print and poll)?

It might be useful considering what you want to place any task that isn't distributable on a specific core so you have an idea what's running where and be able to estimate what usage should be for the core. Could you change your variables to unsigned ints instead of short ints as well since they're your counters and see if there is any change?
mozcelikors
Experienced Member
Posts: 75
Joined: Sat May 07, 2016 11:47 am

Post by mozcelikors »

Hello,
Thanks for the reply. The thing is load is the only thing we know that is 50%, but I cant seem to get efficient information at all for the other tasks. (and also their core number seems nonconsistent, I wonder that). My sole purpose is to say for an event-driven task, get the core usage info, but no value changes real-time. And the weird behavior you saw happens when core placement is changed.

I know the task names doesnt tell much, but the tasks are usually event driven, either using interface that is connected to hardware, and/or timer based, and/or receiving data from another task via an interface. That I think is really typical coding methodology for xCORE. Therefore, I expected seeing some correct figures. (at least for that tasks that involves activity, maybe not the driver-related ones)

- 1 x Task that polls over I2C every 0.2sec
- 3 x Task that controls PWM signal 0-20ms (Control light system, control motor, control steering)
- 1 x Task that manages tcp server (read asynchronously) + send over tcp every 5 sec.
- 1 x Task that reads over uart + makes calculations + produces an output + sends it to another task
- 2 x Task monitoring tasks themselves.
- Some driver related tasks : gpio, i2c, uart, tcp, phy etc...



XMOS is configured to send all core usage info over ethernet to a display (without printf). So I can see all the correct values on that display, they don't change much. For now, I didnt see a woresome part that is related to "printf".

My poll period 10ms
print period 1000ms.

- Using unsigned int's didnt change things, unfortunately..
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

Hi,
I cannot explain what is going awry here and obviously can't reproduce with partial source.
So I took the body of the cpu usage monitor and added a quick bit of test code; basically a set of "burn" tasks which waggle an I/O pin for a burst of a given length periodically, to show usage.

My conclusions are that the method of reading core inuse and core waiting by sampling seem sound:

Code: Select all

Burn task 6 on core ID 0
Burn task 0 on core ID 1
Burn task 1 on core ID 2
Burn task 2 on core ID 3
Burn task 3 on core ID 4
Burn task 4 on core ID 5
Burn task 5 on core ID 6
Starting monitor task on core ID 7
tile[8002]: 87% 0% 15% 29% 42% 54% 73% 100%
tile[8002]: 87% 0% 16% 29% 44% 55% 69% 100%
tile[8002]: 83% 0% 12% 29% 44% 56% 71% 100%
tile[8002]: 85% 0% 13% 27% 41% 58% 69% 100%
...
However, as mentioned by others, this method may not yield terribly useful results. A mostly idle core may miss event deadlines and a mostly busy core may hit every deadline; it all depends on your system.

Anyhow, here's the source that worked for me. I made a few tweaks but nothing fundamental. It's all in a single source file so hopefully you can reproduce this easy enough.

Also, as mentioned by Gothmag, be careful of printing. Make sure you enable xscope printing. Short summary of why here:

http://www.xcore.com/forum/viewtopic.php?f=47&t=4088


Here's the working example:

Code: Select all

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

#define PRINT_MS 100000
#define POLLING_MS 1231

out port p_tog[8] = {XS1_PORT_1A, XS1_PORT_1B, XS1_PORT_1C, XS1_PORT_1D, XS1_PORT_1E, XS1_PORT_1F, XS1_PORT_1G, XS1_PORT_1H};

[[combinable]]
void Task_MonitorCoresInATile(void)
{
      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];
      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();

      printf("Starting monitor task on core ID %d\n", get_logical_core_id());

      while(1)
      {
            select {
                  case print_tmr when timerafter(print_time) :> void:
                        for (t = 0; t <= 7; t++){
                            int numerator = (core_busy[t] * 100);
                            int denominator = (core_idle[t] + core_busy[t]);
                            if (denominator) {
                                core_usage[t] = numerator / denominator;
                            }
                            else {
                                core_usage[t] = 0;
                            }
                        }
#if 1
                        printf("tile[%x]: %d%% %d%% %d%% %d%% %d%% %d%% %d%% %d%%\n",tile_id, 
                                                          core_usage[0],
                                                          core_usage[1],
                                                          core_usage[2],
                                                          core_usage[3],
                                                          core_usage[4],
                                                          core_usage[5],
                                                          core_usage[6],
                                                          core_usage[7]);

#endif

                        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) {
                                      if (waiting) {
                                          core_idle[t] += 1;
                                      } else {
                                          core_busy[t] += 1;
                                      }
                                      //printf("thread %d waiting %d\n", t, waiting);
                              }

                        }
                        poll_time += POLLING_MS;
                        break;
            }
      }
}

#define BURN_PERIOD 10000

//This task periodically toggles an I/O a preset number of times.
//IO toggles cannot be optimised out and so are a good way of burning cycles
void test_task(int burn_rate, out port p){
  timer tmr;
  int time_trig;
  tmr :> time_trig;
  printf("Burn task %d on core ID %d\n", burn_rate, get_logical_core_id());
  while(1){
    select { //Only do if non-zero (guard on case)
      case burn_rate => tmr when timerafter(time_trig + BURN_PERIOD) :> time_trig:
        for (int i=0; i<burn_rate*100; i++){
          p <: i;
        }
        break;
    }
  }
}

int main(void){
  par{
    Task_MonitorCoresInATile();
    par (int c=0; c < 7; c++) test_task(c, p_tog[c]);
  }
  return 0;
}
Gothmag
XCore Addict
Posts: 129
Joined: Wed May 11, 2016 3:50 pm

Post by Gothmag »

Well since as infiniteimprobability has shown the code does seem to work just fine, I would assume your poll time is too slow for your tasks, which seem to be mostly slow tasks. I'm just not sure if the polling is going to hold up other tasks or anything so you will have to watch the actual function.

If you can dedicate a core to it you can try, make sure you're using unsigned ints, to have the polling done under a default case. The more often you poll the more likely you are to catch the cores state at any given moment giving you more accurate information. Remove the load task if its just a busying task too. You could also filter out the core with the core usage task for reporting, it should always report 100 anyway.
mozcelikors
Experienced Member
Posts: 75
Joined: Sat May 07, 2016 11:47 am

Post by mozcelikors »

Thanks again. I am really trying to fix it but it doesnt seem like I'm progressing.

Code: Select all

on tile[0]:                   Task_MonitorCoresInATile (core_stats_interface_tile0);
on tile[1].core[1]:           Task_MonitorCoresInATile (core_stats_interface_tile1);

Code: Select all

Starting monitor task on core ID 5
Starting monitor task on core ID 2
Don't you think this is also weird? Should the core ID be 1?

Also:

Code: Select all

on tile[0].core[2]:                   Task_MonitorCoresInATile (core_stats_interface_tile0);
     on tile[1].core[1]:           Task_MonitorCoresInATile (core_stats_interface_tile1);

Starting monitor task on core ID 4
Starting monitor task on core ID 2
mozcelikors
Experienced Member
Posts: 75
Joined: Sat May 07, 2016 11:47 am

Post by mozcelikors »

Guys, let me just talk about only 1 task:
A task that toggles two ports, both 0-20ms pwm signals.

<Please just copy it to a main.xc and test it, everything included.>

Code: Select all

#include <xs1.h>
#include <platform.h>
#include <gpio.h>

#include <print.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

#define MICROSECOND             (XS1_TIMER_HZ / 1000000)
#define MILLISECOND             (1000 * MICROSECOND)
//Defines for monitoring cores
#define ONE_MS_TICKS 100000
#define POLLING_MS 700 //(10 * ONE_MS_TICKS)
#define PRINT_MS 100000 //(1000 * ONE_MS_TICKS)

on tile[0] : port PortLightSystem_TH = XS1_PORT_1K;  //J12  P1K
on tile[0] : port PortLightSystem_ST = XS1_PORT_1H;  //J13  P1H

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

      print_time = poll_time + PRINT_MS;

      unsigned int core_busy[8];
      unsigned int core_idle[8];
      unsigned 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();
      int cntr = 0;

      printf("Starting monitor task on core ID %d\n", get_logical_core_id());

      while(1)
      {
            select {
                  case print_tmr when timerafter(print_time) :> void:
                        /*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++) {
                                  int numerator = (core_busy[t] * 100);
                                  int denominator = (core_idle[t] + core_busy[t]);
                                  if (denominator) {
                                      core_usage[t] = core_usage[t] + numerator / denominator;

                                  } else {
                                      core_usage[t] = core_usage[t] + 0;
                                  }
                          }
                          cntr = cntr + 1;
                          if (cntr == 5)
                          {
                                  if (core_usage[0]>=0 && core_usage[0]<=500)
                                  {
                                      /*core_stats_interface.ShareCoreUsage (core_usage[0] /5,
                                                                         core_usage[1] /5,
                                                                         core_usage[2] /5,
                                                                         core_usage[3] /5,
                                                                         core_usage[4] /5,
                                                                         core_usage[5] /5,
                                                                         core_usage[6] /5,
                                                                         core_usage[7] /5);*/
                                      printf("tile[%x]: %d %d %d %d %d %d %d %d\n\n",tile_id, core_usage[0] /5,
                                                                        core_usage[1] /5,
                                                                        core_usage[2] /5,
                                                                        core_usage[3] /5,
                                                                        core_usage[4] /5,
                                                                        core_usage[5] /5,
                                                                        core_usage[6] /5,
                                                                        core_usage[7] /5);

                                      for (t = 0; t <= 7; t++) {
                                          core_usage[t] = 0;
                                      }
                                      cntr = 0;
                                  }
                                  else
                                  {
                                        for (t = 0; t <= 7; t++) {
                                            core_usage[t] = 0;
                                        }
                                        cntr = 0;
                                  }
                        }

                        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) {
                                      if (waiting) {
                                          core_idle[t] += 1;
                                      } else {
                                          core_busy[t] += 1;
                                      }
                              }

                        }
                        poll_time += POLLING_MS;
                        break;
            }
      }
}


[[combinable]]
void Task_ControlLightSystem (port p_TH, port p_ST)
{
    uint32_t overall_pwm_period = 20*MILLISECOND ;
    uint32_t on_period_TH,  on_period_ST;
    uint32_t off_period_TH, off_period_ST;

    uint32_t    time_TH, time_ST;
    int         port_state_TH = 0;
    int         port_state_ST  = 0;
    int         toggle_port_TH = 0;
    int         toggle_port_ST = 0;
    timer       tmr_TH, tmr_ST;

    int lightstate_val;

    //Initialization for some variables
    lightstate_val = 1;
    on_period_ST = 1.7*MILLISECOND;
    on_period_TH = 1.5*MILLISECOND;
    off_period_ST = overall_pwm_period - on_period_ST;
    off_period_TH = overall_pwm_period - on_period_TH;


    while(1)
    {
        select
        {

            //Port p_ST PWM Timer Event
            case tmr_ST when timerafter(time_ST) :> void :

                tmr_ST :> time_ST;

                //PWM Port Toggling
                if(port_state_ST == 0)
                {
                    p_ST <: 1;
                    port_state_ST = 1;
                    time_ST += on_period_ST; //Extend timer deadline
                }
                else if(port_state_ST == 1)
                {
                    p_ST <: 0;
                    port_state_ST = 0;
                    time_ST += off_period_ST; //Extend timer deadline
                }

                break;

            //Port p_TH PWM Timer Event
            case tmr_TH when timerafter(time_TH) :> void :

                tmr_TH :> time_TH;

                //PWM Port Toggling
                if(port_state_TH == 0)
                {
                    p_TH <: 1;
                    port_state_TH = 1;
                    time_TH += on_period_TH; //Extend timer deadline
                }
                else if(port_state_TH == 1)
                {
                    p_TH <: 0;
                    port_state_TH = 0;
                    time_TH += off_period_TH; //Extend timer deadline
                }

                break;
        }
    }
}

int main() {
par {
on tile[0].core[6]:              Task_ControlLightSystem (PortLightSystem_TH, PortLightSystem_ST);

on tile[0].core[2]:                   Task_MonitorCoresInATile ();
}
return 0;
}

Even for this function, I cant get any output, when its the only thing thats active along with the Monitoring task.

Output:

Code: Select all

tile[8002]: 0 0 0 0 0 0 0 0
For the monitoring I have,

Code: Select all

#define ONE_MS_TICKS 100000
#define POLLING_MS 700 //(10 * ONE_MS_TICKS)
#define PRINT_MS 100000 //(1000 * ONE_MS_TICKS)

What do you think? I think if I can see core usage for this task, then maybe others will be easier.
Could you please try running your code on this to see if it really works? I removed every dependent function and interface so you could easily try it.
This involves a lot of port toggling so I think I should be able to monitor this one at least.

Thanks again..
Gothmag
XCore Addict
Posts: 129
Joined: Wed May 11, 2016 3:50 pm

Post by Gothmag »

Code: Select all

/*
 * usage test.xc
 *
 *  Created on: Dec 5, 2016
 *      Author: Justin
 */

#include <xs1.h>
#include <platform.h>
#include <stdio.h>
#include <timer.h>

#define PORTATIME 160
#define PORTBTIME 90
#define CYCLETIME 1250
on tile[0] : port PortLightSystem_TH = XS1_PORT_1K;  //J12  P1K
on tile[0] : port PortLightSystem_ST = XS1_PORT_1H;  //J13  P1H

void Task_MonitorCoresInATile() {
    int t;
    timer poll_tmr, print_tmr;
    int poll_time, print_time;
    poll_tmr :> poll_time;

    print_time = poll_time + XS1_TIMER_HZ;

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

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

int tile_id = get_local_tile_id();
int cntr = 0;

while (1) {
    select {
        case print_tmr when timerafter(print_time) :> void:
        for (t = 0; t <= 7; t++) {
            float numerator = (core_busy[t] * 100.0f);
            float denominator = (core_idle[t] + core_busy[t]);
            if (denominator) core_usage[t] += numerator / denominator;
        }
        cntr = cntr + 1;
        if (cntr == 5)
        {
            for (int i = 0; i < 8; ++i) core_usage[i] /= 5.0f;
                printf("tile[%x]: %3.2f %3.2f %3.2f %3.2f %3.2f %3.2f %3.2f %3.2f\n\n",tile_id, 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_usage[t] = 0.0f;
                cntr = 0;
        }
        for (t = 0; t <= 7; t++) {
            core_busy[t] = 0;
            core_idle[t] = 0;
        }
        print_time += XS1_TIMER_HZ;
        break;

        default:
        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) {
                if (waiting) core_idle[t] += 1;
                else core_busy[t] += 1;
            }
        }
        break;
    }
}
}

void Task_ControlLightSystem(port p_TH, port p_ST) {
unsigned int overall_pwm_period = CYCLETIME;
unsigned int on_period_TH, on_period_ST;
unsigned int off_period_TH, off_period_ST;

unsigned int time_TH, time_ST;
int port_state_TH = 0;
int port_state_ST = 0;
timer tmr_TH, tmr_ST;

int lightstate_val;

//Initialization for some variables
lightstate_val = 1;
on_period_ST = PORTATIME;
on_period_TH = PORTBTIME;
off_period_ST = overall_pwm_period - on_period_ST;
off_period_TH = overall_pwm_period - on_period_TH;

while (1) {
    select
    {

        //Port p_ST PWM Timer Event
        case tmr_ST when timerafter(time_ST) :> void :

        tmr_ST :> time_ST;

        //PWM Port Toggling
        if(port_state_ST == 0)
        {
            p_ST <: 1;
            port_state_ST = 1;
            time_ST += on_period_ST; //Extend timer deadline
        }
        else if(port_state_ST == 1)
        {
            p_ST <: 0;
            port_state_ST = 0;
            time_ST += off_period_ST; //Extend timer deadline
        }

        break;

        //Port p_TH PWM Timer Event
        case tmr_TH when timerafter(time_TH) :> void :

        tmr_TH :> time_TH;

        //PWM Port Toggling
        if(port_state_TH == 0)
        {
            p_TH <: 1;
            port_state_TH = 1;
            time_TH += on_period_TH; //Extend timer deadline
        }
        else if(port_state_TH == 1)
        {
            p_TH <: 0;
            port_state_TH = 0;
            time_TH += off_period_TH; //Extend timer deadline
        }

        break;
    }
}
}

int main() {
par {
    on tile[0]: Task_ControlLightSystem(PortLightSystem_TH,
            PortLightSystem_ST);

    on tile[0]: Task_MonitorCoresInATile();
}
return 0;
}
Try this. Your example was almost always idle. I've sped up the polling rate to the fastest you really can. I've also sped up your cycle time and port toggle time. You can change them using PORTATIME, PORTBTIME, and CYCLETIME in the defines at the top. Increasing CYCLETIME will decrease usage. You can play with it and see how it changes.

So I think your problem is an issue of your polling time, your print speed, and the actual "busy-ness" of your cores. I tested on a startkit because it's what I had near me. On the startkit, at the very least, the printf halts the entire processor, so if you print too fast nothing else ever really happens to let the processor get busy resulting in all 0's for every print. It'll print roughly once every 5 seconds, because of your 5 print cycle averaging.
mozcelikors
Experienced Member
Posts: 75
Joined: Sat May 07, 2016 11:47 am

Post by mozcelikors »

Thanks for trying that out. Your comments are really helpful.
For the debug_printf, I have included config.xscope and selected xSCOPE from the Run Configurations,
But I seem to be getting the following and no more prints:

Code: Select all

WARNING: tile[0] - xSCOPE not supported by application, I/O will be via JTAG
WARNING: tile[1] - xSCOPE not supported by application, I/O will be via JTAG
config.xscope

Code: Select all

<xSCOPEconfig enabled="true" ioMode="basic">
</xSCOPEconfig>
xrun -l results in this:

Code: Select all

Available XMOS Devices
----------------------

  ID	Name			Adapter ID	Devices
  --	----			----------	-------
  0 	XMOS XTAG-3         	0y0HQ0n3	O[0]

Makefile:

Code: Select all

# The TARGET variable determines what target system the application is
# compiled for. It either refers to an XN file in the source directories
# or a valid argument for the --target option when compiling.

TARGET = XCORE-200-EXPLORER

# The APP_NAME variable determines the name of the final .xe file. It should
# not include the .xe postfix. If left blank the name will default to
# the project name
APP_NAME = RCBuild15

# The flags passed to xcc when building the application
# You can also set the following to override flags for a particular language:
#
#    XCC_XC_FLAGS, XCC_C_FLAGS, XCC_ASM_FLAGS, XCC_CPP_FLAGS
#
# If the variable XCC_MAP_FLAGS is set it overrides the flags passed to
# xcc for the final link (mapping) stage.

XCC_FLAGS = -Wall -O3 -report -fxscope -DDEBUG_PRINT_ENABLE=1
XCC_XC_FLAGS = -report
XCC_C_FLAGS = -report
XCC_CPP_FLAGS = -report
XCC_MAP_FLAGS = -report
XCC_ASM_FLAGS = -report

SOURCE_DIRS = src
INCLUDE_DIRS = src

# The USED_MODULES variable lists other module used by the application.
USED_MODULES = lib_ethernet lib_gpio lib_i2c lib_locks lib_logging lib_otpinfo lib_uart lib_xassert lib_xtcp

#=============================================================================
# The following part of the Makefile includes the common build infrastructure
# for compiling XMOS applications. You should not need to edit below here.

XMOS_MAKE_PATH ?= ../..
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

VERBOSE = 1
But then again, even though I dont have that printf at all, I can monitor the cores over ethernet, and they are the same. Still it would be useful to fix this warning related to debug_printf.