Updated: April 19, 2023 |
As mentioned above, the shared memory region is divided into two sections, each beginning on a 4 KB page boundary. The first section contains the adios_signature_t, followed by the adios_daq_status_t, followed by one adios_cis_t for each installed card.
Suppose that we have one PCL-711 card and one DIO-144 installed. This is what the first part of the memory layout will look like:
Offset (bytes) | Name | Size (bytes) | Description | Value |
---|---|---|---|---|
adios_signature_t | ||||
0000 | signature | 4 | Signature | "ADIO" |
0004 | datablock | 4 | Datablock; which 4 KB page the data section starts on | 1 |
0008 | num_cis | 4 | Number of entries in the CIS | 2 |
000C | num_elems | 4 | Size of the ring buffer | 2000 |
adios_daq_status_t | ||||
0010 | head | 4 | Index to the newest valid and stable data element | 0 |
0014 | tail | 4 | Index to the oldest valid and stable data element | 99 |
0018 | element_size | 4 | Size of each element, including any padding | 52 |
adios_cis_t | ||||
001C | name | 128 | Name of the device | /dev/pcl711-02d0 |
009C | nai | 4 | Number of analog inputs | 8 |
00A0 | nao | 4 | Number of analog outputs | 1 |
00A4 | ndi | 4 | Number of digital inputs | 16 |
00A8 | ndo | 4 | Number of digital outputs | 16 |
00AC | nbpc | 4 | Number of bytes per channel | 2 |
00B0 | maxresai | 4 | Maximum bit resolution of analog input | 12 |
adios_cis_t | ||||
00B4 | name | 128 | Name of the device | /dev/dio144-0220 |
0134 | nai | 4 | Number of analog inputs | 0 |
0138 | nao | 4 | Number of analog outputs | 0 |
013C | ndi | 4 | Number of digital inputs | 144 |
0140 | ndo | 4 | Number of digital outputs | 144 |
0144 | nbpc | 4 | Number of bytes per channel | 3 |
0148 | maxresai | 4 | Maximum bit resolution of analog input | 0 |
014C–0FFF | Filler |
The second part of the shared memory contains the data. Each data set consists of a tiny adios_data_header_t followed by the samples from the various cards. There are as many data sets as specified with the command line -S option (or the default of 1000).
Continuing with our example of the two cards from above, here's what the first and part of the second data set look like:
Offset (bytes) | Name | Size (bytes) | Description |
---|---|---|---|
adios_data_header_t | |||
1000 | t0ns | 8 | Beginning of snapshot 0 time |
1008 | t1ns | 8 | End of snapshot 0 time |
(Data) | |||
1010 | ai0 | 2 | PCL-711 analog input channel 0 sample |
1012 | ai1 | 2 | PCL-711 analog input channel 1 sample |
1014 | ai2 | 2 | PCL-711 analog input channel 2 sample |
1016 | ai3 | 2 | PCL-711 analog input channel 3 sample |
1018 | ai4 | 2 | PCL-711 analog input channel 4 sample |
101A | ai5 | 2 | PCL-711 analog input channel 5 sample |
101C | ai6 | 2 | PCL-711 analog input channel 6 sample |
101E | ai7 | 2 | PCL-711 analog input channel 7 sample |
1020 | di | 2 | PCL-711 digital input channel 8 (16 bits) |
1022 | di | 18 | DIO-144 digital input channel 0–5 samples |
adios_data_header_t | |||
1034 | t0ns | 8 | Beginning of snapshot 1 time |
103C | t1ns | 8 | End of snapshot 1 time |
(Data) | |||
1044 | ai0 | 2 | PCL-711 analog input channel 0 sample |
1046 | ai1 | 2 | PCL-711 analog input channel 1 sample |
... | ... |
Therefore, the first job of create_shmem() is to figure out the sizes of the various data structures.
void create_shmem (void) { int size; int size_c, size_d; int size_d_ai, size_d_di; int size_element; int i; int sts; // size_c is the control section size size_c = sizeof (adios_signature_t) + sizeof (adios_cis_t) * nadios; // size_d is the data section size size_d = sizeof (adios_data_header_t); for (i = 0; i < nadios; i++) { size_d_ai = adios [i].nai * ((adios [i].maxresai + 15) / 16) * 2; size_d_di = (adios [i].ndi + 31) / 32 * 4; size_d += size_d_ai + FILLER_ALIGN_32bits (size_d_ai) + size_d_di; } size_element = size_d; size_d *= optS; // compute the total size of shared memory size = size_c + FILLER_ALIGN_4kbytes (size_c) + size_d + FILLER_ALIGN_4kbytes (size_d); ...
As you can see, the code runs through the adios global database that it filled in as the final phase of option processing, and accumulates the total data sizes that all of the samples will need. The optS variable is the number of samples; once we know each sample's size we multiply by that number to compute the total size. The total size of the shared memory is size_c (rounded up to be a multiple of 4096 bytes) plus size_d (also rounded up).