Calculating the sizes of data structures

Updated: May 06, 2022

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).