Store atomicity Topic is solved

If you have a simple question and just want an answer.
User avatar
lukehatpadl
Active Member
Posts: 38
Joined: Sat Jul 08, 2023 5:15 am

Store atomicity

Post by lukehatpadl »

Currently I have a control task on tile 0 that communicates with a number of tasks on tiles 2 and 3. This consumes a lot of chanends. I was thinking of having a broker/manager process on tile 2 and 3 that consumed the control information and stored it in shared memory.

Are word reads and writes atomic on XS2 or do I need to use locks?
View Solution
User avatar
Ross
Verified
XCore Legend
Posts: 1158
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Word reads/writes are atomic, there are single word (32bit) load and store instructions.

You could read/write a couple of words atomically by targeting the double word (64bit) access instructions.
Technical Director @ XMOS. Opinions expressed are my own
User avatar
lukehatpadl
Active Member
Posts: 38
Joined: Sat Jul 08, 2023 5:15 am

Post by lukehatpadl »

Thanks Ross!

Interestingly I am getting ET_LOAD_STORE when I try to write. Here's a simplified version of the code:

Code: Select all

// 64-bit word stores 16-bit LR gains as well as various flags
static uint64_t __control[NUM_MIXER_OUTPUTS];
xc_ptr gControl;

void
init(void) {
  SET_SHARED_GLOBAL(gControl, long_long_array_to_xc_ptr(& __control[0]));
}

xc_ptr getBasePointer(void)
{
  xc_ptr basePointer;
  GET_SHARED_GLOBAL(basePointer, gControl);
  return basePointer;
}

static inline void
setGain(xc_ptr basePointer, uint8_t outputChannel, uint16_t lgain, uint16_t rgain)
{
  uint32_t lrgain = (lgain ≪ 16) | rgain;
  
  // *2 because accessing 32-bit offset
  write_long_via_xc_ptr_indexed(lrgain, (size_t)(2 * outputChannel), basePointer);
}

void
runTask()
{
...
  setGain(getBasePointer(), 0, 0, 0);
...
}
long_long_array_to_xc_ptr() is the same as the other variants, I wanted 64-bit alignment so I can potentially read 64-bit words as you described above.

I wasn't sure if SET/GET_SHARED_GLOBAL() are necessary or indeed whether I could just declare the global variables in C rather than XC. I tried many permutations all which raised ET_LOAD_STORE.
Last edited by lukehatpadl on Mon Oct 07, 2024 7:27 am, edited 1 time in total.
User avatar
lukehatpadl
Active Member
Posts: 38
Joined: Sat Jul 08, 2023 5:15 am

Post by lukehatpadl »

Possibly related question: does each tile get its own copy of global variables? I presume so.

Followup question: is there a preprocessor macro I can use to determine the current tile at compile time? Could be useful for adding some safety checks.
User avatar
Ross
Verified
XCore Legend
Posts: 1158
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

SET/GET_SHARED_GLOBAL macros in the USB Audio codebase hark back to the days with xc didn't have any support for pointers - so inline asm was used.

These days you're better off using an "unsafe" pointers:

Code: Select all

#include <print.h>

long long var;

int main()
{
    unsafe
    {
        long long * unsafe ptr = &var;

        *ptr = 100LL;

        printllongln(*ptr);
    }
}
Technical Director @ XMOS. Opinions expressed are my own
User avatar
Ross
Verified
XCore Legend
Posts: 1158
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Each tile will have its own independent version of each global.

Not aware of anything in the preprocessor, but you could use

Code: Select all

unsigned get_local_tile_id(void);
Technical Director @ XMOS. Opinions expressed are my own
User avatar
lukehatpadl
Active Member
Posts: 38
Joined: Sat Jul 08, 2023 5:15 am

Post by lukehatpadl »

Ross wrote: Mon Oct 07, 2024 12:30 pm SET/GET_SHARED_GLOBAL macros in the USB Audio codebase hark back to the days with xc didn't have any support for pointers - so inline asm was used.

These days you're better off using an "unsafe" pointers:
Thanks! This is more elegant, although I still needed to use the macros for initialising the global to avoid the parallel usage error.

Compiles:

Code: Select all

  SET_SHARED_GLOBAL(gOutputMixerControl,
                    long_long_array_to_xc_ptr(&__gOutputMixerControl[0]));
Does not compile (if the variable is accessed elsewhere):

Code: Select all

  unsafe {
    gOutputMixerControl = long_long_array_to_xc_ptr(&__gOutputMixerControl[0]);
  }
Now I don't think this will address the ET_LOAD_STORE exception, but I shall keep investigating that today.
User avatar
lukehatpadl
Active Member
Posts: 38
Joined: Sat Jul 08, 2023 5:15 am

Post by lukehatpadl »

FWIW, I resolved the ET_LOAD_STORE exception issue by just migrating the code that wrote to the array to C. When I have a moment I'll compare the assembly output to see exactly what's going on. I'm still using the xc_ptr.h helpers on the read side.