Hi,
I just started to learn XMOS. In between tasks, we can use notification to do asynchronous communication.
What is the cost of an interface notification in terms of CPU cycles? For example, if the clear_notification defined by client does nothing, how many cycles does it take from the client calls notification to the client finishes clear_notification if the server is able to process the notification when the client calls it.
I wanted to know the best granularity of each task. Intuitively if a task is too small, the communication cost may dominate. If the timing analysis tool can report the time between endpoints, do we document costs of all kinds of XC instructions?
Thank you,
J
interface notification cost
-
- New User
- Posts: 2
- Joined: Thu Oct 15, 2015 4:56 pm
-
Verified
- XCore Legend
- Posts: 1164
- Joined: Thu May 27, 2010 10:08 am
I did a quick test and setting a notfication is in the order of 140ns (4 cores running) and clearing a notification was quite long, for an empty notification clear case - about 380ns.
Remember that setting a notification is an asycchronous event and so you don't have to wait for anything at the client end, however clearing the notification will block until the clears notification case is executed, which maintains synchronisation.
Underneath it uses channels for the mechanism. Here's some test code for your own experiements!
#include <xs1.h>
#include <stdio.h>
#define NOTIFICATION 1
#define INTERVAL_1 100000 //1ms
#define INTERVAL_2 150000 //1.5ms
interface do_things{
[[notification]] slave void notify(void);
int read(int idx);
[[clears_notification]] void notification_clear(void);
};
int start_time, end_time;
timer t_perf;
static inline void start(void){
t_perf :> start_time;
}
static inline void stop(void){
t_perf :> end_time;
printf("Time taken = %d ns\n", 10*(end_time - start_time));
}
[[combinable]]
void client_task(client interface do_things i_things){
timer t_interval;
int next_interval;
t_interval :> next_interval;
next_interval += INTERVAL_1;
while (1){
select{
case t_interval when timerafter (next_interval) :> void:
next_interval += INTERVAL_1;
printf("tick client\n");
break;
#if NOTIFICATION
case i_things.notify():
int val = i_things.read(0);
start();
i_things.notification_clear();
stop();
break;
#endif
}
}
}
[[combinable]]
void server_task(server interface do_things i_things){
timer t_interval;
int next_interval;
t_interval :> next_interval;
next_interval += INTERVAL_2;
while(1){
select{
case i_things.read(int idx) -> int val:
delay_microseconds(1);
break;
case i_things.notification_clear():
delay_microseconds(1);
break;
#if NOTIFICATION
case t_interval when timerafter (next_interval) :> void:
next_interval += INTERVAL_2;
printf("tick server\n");
//start();
i_things.notify();
//stop();
break;
#endif
}
}
}
int main() {
interface do_things i_things;
//[[combine]]
par{
server_task(i_things);
client_task(i_things);
}
return 0;
}
Remember that setting a notification is an asycchronous event and so you don't have to wait for anything at the client end, however clearing the notification will block until the clears notification case is executed, which maintains synchronisation.
Underneath it uses channels for the mechanism. Here's some test code for your own experiements!
#include <xs1.h>
#include <stdio.h>
#define NOTIFICATION 1
#define INTERVAL_1 100000 //1ms
#define INTERVAL_2 150000 //1.5ms
interface do_things{
[[notification]] slave void notify(void);
int read(int idx);
[[clears_notification]] void notification_clear(void);
};
int start_time, end_time;
timer t_perf;
static inline void start(void){
t_perf :> start_time;
}
static inline void stop(void){
t_perf :> end_time;
printf("Time taken = %d ns\n", 10*(end_time - start_time));
}
[[combinable]]
void client_task(client interface do_things i_things){
timer t_interval;
int next_interval;
t_interval :> next_interval;
next_interval += INTERVAL_1;
while (1){
select{
case t_interval when timerafter (next_interval) :> void:
next_interval += INTERVAL_1;
printf("tick client\n");
break;
#if NOTIFICATION
case i_things.notify():
int val = i_things.read(0);
start();
i_things.notification_clear();
stop();
break;
#endif
}
}
}
[[combinable]]
void server_task(server interface do_things i_things){
timer t_interval;
int next_interval;
t_interval :> next_interval;
next_interval += INTERVAL_2;
while(1){
select{
case i_things.read(int idx) -> int val:
delay_microseconds(1);
break;
case i_things.notification_clear():
delay_microseconds(1);
break;
#if NOTIFICATION
case t_interval when timerafter (next_interval) :> void:
next_interval += INTERVAL_2;
printf("tick server\n");
//start();
i_things.notify();
//stop();
break;
#endif
}
}
}
int main() {
interface do_things i_things;
//[[combine]]
par{
server_task(i_things);
client_task(i_things);
}
return 0;
}
Engineer at XMOS