time measurement

25 posts / 0 new
Last post
Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26
time measurement

Hello,

In my project, I want to do time measurement. I mean that i want to measure the time when my message is sending until it is receiving in the Subscriber. I want to print out this kind of measurement. What should i do in Publisher and in Subscriber?

Pc's are different, they are in connection by TCP protocol.

Would you please help me?

Best Regards,

Ehsan

 

Offline
Last seen: 1 year 3 months ago
Joined: 05/23/2013
Posts: 64

Ehsan,

To measure latency from a publisher to a subscriber, you can do two different ways if pub/sub entities are located in different machines like your case. 
The main issue is that time is not synchronized in different machines.

First, you can use Precise Time Protocol (PTP) to synchronize time on both machines, which guarantees more accurate time synchronization than NTP. 
If you are using Ubuntu machines, it is easy to install and run on your machines like following. It uses multicast as a default, but if your network does not support multicast, you can use unicast option too. 
# apt-get install ptpd
# ptpd

After installing PTP, what you can do is to get a timestamp on a publisher and stores the timestamp value in your message and send it to a subscriber.
In the subscriber, you can get a timestamp like the publisher and extract the timestamp value of the publisher from the received message and calculate latency with two timestamp values. 

Second, you can measure round-trip time of a message and half the time to measure one-way latency. In this case, you do not need to synchronize time between machines as you use tiemstamps on a single machine. 
RTI DDS Performance Test measures the time in this way. You can refer to this link to try it out. 
https://community.rti.com/kb/example-performance-test-rti-message-service

Thanks,
Kyoungho

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Thank you for your help. PTP is working on the PCs. But how can i access to the variables in the Subscriber?

 I have 3 Data writers and i receive my data in Subscriber by order-group. for example, How can i access to variable 'w' which is read by DataReader2 in Subscriber?

my IDL file is:

const long CLOCK_MAX_STRING_SIZE = 256;
struct Type1 {
long x;
long y;
string<CLOCK_MAX_STRING_SIZE> message;  //@key

};


struct Type2 {

long w;
long z;
string<CLOCK_MAX_STRING_SIZE> message;  //@key
};



struct Type3 {

long p;
long t;
string<CLOCK_MAX_STRING_SIZE> message;  //@key
};


struct ordered_group {
Type1 msg1;
Type2 msg2;
Type3 msg3;

};

Offline
Last seen: 1 year 3 months ago
Joined: 05/23/2013
Posts: 64

Hi Ehsan,

I assume that your work is based on the ordered presentation group example in this link.
https://community.rti.com/examples/ordered-presentation-group

If so, the way to access variables in each type is simple like following. 

ordered_group data;
// skip the code to take data from a DataReader
if (info.valid_data) {  
  int x = data.msg1.x;
  int y = data.msg1.y;  
}    

I am not sure this would be an answer to your question. Please let me know if it was not the question you were asking. 
Could I ask you one thing? For me, It looks like all 3 types (Type1, Type2, Type3) are the same. Why would you have three different types that define the same thing?

Thanks,
Kyoungho

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Really Thanks. but there is problem. in each time that i want to show the received data, data which is received for exaple by DataReader1 is shown and the others are "0". I think it is because of the order of data which is received by darareaders. How can i show the real data without any "0"'s.

my output is like this:

msg1:
      x: 0
      y: 0
      message: ""
   msg2:
      w: 0
      z: 0
      message: ""
   msg3:
      p: 880166
      t: 30
      message: ""

in this instance i want to show just msg3. What should i do?

About your Question i should say that, I want to send 3 different packets of variables. i thought that if i deffine 3 type it is easier to access to my data and each variable. What do you think? is it wrong?

 

 

Offline
Last seen: 4 years 5 months ago
Joined: 09/10/2010
Posts: 32

Hello,

Can you describe your publishing scenario a little more?  This may help with a better response to achieve what you are looking for.    Are you publishing each message type independently?  Do you need them grouped together for coherent access?  Have you thought about having a different type that has the following structure:

struct msg {

string type;  //@key

string message; //@key

long var1;

long var2;

};

That way you don't have the msg types that are in the payload that aren't being populated.  You can just collect all messages from all types and have independent history on a per type basis.

Bert

 

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Actually, I made a Test case on that way to understand what should i do. in that test case, In the Publisher i wanted to send 3 packages of Data as some Messages such as msg1 or msg2 or msg3.  I decided to make DataWriters in the number of my Messages. I made one instance of my "ordered_group" struct for each message. i put the values to the variables which are related to each Message and then each Datawriter send each insatnce.

------------------------------------------------------------------------

instance1 = ordered_groupTypeSupport::create_data();

instance2 = ordered_groupTypeSupport::create_data();

 instance3 = ordered_groupTypeSupport::create_data();

--------------------------------------------------------------------

instance1->msg1.y=10;

retcode = ordered_group_writer1->write(*instance1, instance_handle);

-------------------------------------------------------------------

 

But the real data which should publish or Subscribe is:

typedef uint16_t  X;

typedef struct Y1 {
    uint16_t bit_id;
    uint8_t  msg_class;
    uint32_t message_code;
    uint32_t occurrences;
    uint8_t  mode;
    uint8_t msg_text[64];
    uint8_t msg_text_length;
}Y1;

typedef struct Z1 {
    uint16_t bit_id;
    uint16_t func_id;
    uint16_t n_objects;
    uint16_t objects[256];
} Z1;

typedef struct Z2 {
    uint16_t bit_id;
    uint16_t func_id;
    uint8_t msg_text[64];
    uint8_t msg_text_length;
}Z2;

 

What do you think? How can i mannage it on the IDL file? I would really appreciate you if you help me.

 

Offline
Last seen: 1 year 3 months ago
Joined: 05/23/2013
Posts: 64

If each DataWriter does not use variables in other types, here is my suggestion. 

struct Y1 {
   unsigned short bit_id;
   octet msg_class;
   unsigned long message_code;
   octet t_mode;
   octet msg_text[64];
   octet msg_text_length;
};
 
struct Z1 {
   // define like Y1  
};
 
struct Z2 {
   // define like Y1 
};  

 

instance1 = Y1TypeSupport::create_data();
instance2 = Z1TypeSupport::create_data();
instance3 = Z2TypeSupport::create_data();

instance1->bit_id = 0;
// fill up data for Y1
writer1->write (*instance1, instance_handle);        

 

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

I've registered 3 Types in both Subscriber and publisher, I wrote my Subscriber part like this:

for(i=0; i<MyDataReaders.length(); i++){

        bite_msg_tDataReader *ordered_group_reader = NULL;
        bite_iam_cmd_tDataReader *ordered_group_reader2 = NULL;
        bite_iam_reply_tDataReader *ordered_group_reader3 = NULL;
        bite_iam_reply_t data3;
        bite_iam_cmd_t data2;
        bite_msg_t data;
                    
        DDS_SampleInfo info;
        DDS_SampleInfo info2;
        DDS_SampleInfo info3;
        bite_msg_t_initialize(&data);
        bite_iam_cmd_t_initialize(&data2);    
        bite_iam_reply_t_initialize(&data3);
       

         ordered_group_reader =
                bite_msg_tDataReader::narrow(MyDataReaders.get_at(i));
        
        if (ordered_group_reader == NULL) {
            printf("DataReader narrow error\n");
            MyDataReaders.ensure_length(0,0);            
            subscriber->end_access();
            return;
        }
         ordered_group_reader2 =
                bite_iam_cmd_tDataReader::narrow(MyDataReaders.get_at(i+1));
       if (ordered_group_reader2 == NULL) {
            printf("DataReader narrow error\n");
            MyDataReaders.ensure_length(0,0);            
            subscriber->end_access();
            return;
        }
         ordered_group_reader3 =
                bite_iam_reply_tDataReader::narrow(MyDataReaders.get_at(i+2));
       if (ordered_group_reader2 == NULL) {
            printf("DataReader narrow error\n");
            MyDataReaders.ensure_length(0,0);            
            subscriber->end_access();
            return;
        }

        retcode = ordered_group_reader->take_next_sample(data, info);
         

        if (retcode == DDS_RETCODE_NO_DATA) {
            continue;
        } else if (retcode != DDS_RETCODE_OK) {
            printf("take error %d\n", retcode);
            continue;
        }


        retcode = ordered_group_reader2->take_next_sample(data2, info2);
          if (retcode == DDS_RETCODE_NO_DATA) {
            continue;
        } else if (retcode != DDS_RETCODE_OK) {
            printf("take error %d\n", retcode);
            continue;
        }


         retcode = ordered_group_reader3->take_next_sample(data3, info3);
          if (retcode == DDS_RETCODE_NO_DATA) {
            continue;
        } else if (retcode != DDS_RETCODE_OK) {
            printf("take error %d\n", retcode);
            continue;
        }

            /* Print data sample */
        if (info.valid_data) {                
            bite_msg_tTypeSupport::print_data(&data);
           
        }
if (info2.valid_data) {                
            bite_iam_cmd_tTypeSupport::print_data(&data2);
           }

if (info3.valid_data) {                
            bite_iam_reply_tTypeSupport::print_data(&data3);
        }



    }
    MyDataReaders.ensure_length(0,0);

    subscriber->end_access();

 

And in the Output (I mean in subscriber side) I received this Error :

message: "Hey, I am X"
   bite_id: 0
   msg_class: <00>
   fault_message_code: 0
   nmuber_of_occurrences: 0
   mode: <00>

   message: "Hey, I am Y"
   bite_id: 0
   func_id: 0
   number_of_objects: 0

   message: "Hey, I am Z"
   bite_id: 0
   func_id: 0
TDataReader::narrow:ERROR: Bad parameter: wrong type reader
DataReader narrow error
DDSDataReaderSeq_get_reference:!assert index out of bounds
Segmentation fault (core dumped)



I've received just one sequence of each Type, and after that i faced with Sequence Error.!!!!!!!!

I don't know how to find a solution for the sequence error. The problem seems not so difficult, but i don't know how to solve it.

rip
rip's picture
Offline
Last seen: 3 days 2 hours ago
Joined: 04/06/2012
Posts: 324

for(i=0; i<MyDataReaders.length(); i++){


shouldn't that be

for (i = 0; i < MyDataReaders.length(); i += 3) {

(from inspection, it looks like your MyDataReaders array is a 3 column, flat multi-dimensional array).

 

 

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Dear Mr.Williamson,

It Doesn't Work !!!!!

I tried this one also after i said my problem here. I also Changed the value of "i" inside of the loop, But Doesn't work.

 

rip
rip's picture
Offline
Last seen: 3 days 2 hours ago
Joined: 04/06/2012
Posts: 324

Hi,

call me rip. 

Here's another problem:

        ordered_group_reader3 =
                bite_iam_reply_tDataReader::narrow(MyDataReaders.get_at(i+2));
       if (ordered_group_reader2 == NULL) {
            printf("DataReader narrow error\n");
            MyDataReaders.ensure_length(0,0);            
            subscriber->end_access();
            return;
        }

cut+paste error.

rip
rip's picture
Offline
Last seen: 3 days 2 hours ago
Joined: 04/06/2012
Posts: 324
    // Assumption is that the array is laid out like
    // [i] msg reader
    // [i+1] cmd reader
    // [i+2] reply reader
    // so increment i by 3 each loop.
    for (i = 0; i < MyDataReaders.length(); i += 3) {
        printf("Loop start, i=%d\n", i);
   
        DDS_SampleInfo msgInfo, cmdInfo, replyInfo;
        DDS_Retcode_t  msgRetcode, cmdRetcode, replyRetcode

        bite_msg_tDataReader *goreader_msg = NULL;
        bite_msg_t     msgData;
   
        bite_iam_cmd_tDataReader *goreader_cmd = NULL;
        bite_iam_cmd_t cmdData;

        bite_iam_reply_tDataReader *goreader_reply = NULL;
        bite_iam_reply_t replyData;

        bite_msg_t_initialize(&msgData);
        bite_iam_cmd_t_initialize(&cmdData);
        bite_iam_reply_t_initialize(&replyData);

        goreader_msg =
            bite_msg_tDataReader::narrow(MyDataReaders.get_at(i));
        if (goreader_msg == NULL) {
            printf("msg DataReader narrow error\n");
            MyDataReaders.ensure_length(0,0);
            subscriber->end_access();
            return;
        }

        goreader_cmd =
            bite_iam_cmd_tDataReader::narrow(MyDataReaders.get_at(i+1));
        if (goreader_cmd == NULL) {
            printf("cmd DataReader narrow error\n");
            MyDataReaders.ensure_length(0,0);
            subscriber->end_access();
            return;
        }

        goreader_reply =
            bite_iam_reply_tDataReader::narrow(MyDataReaders.get_at(i+2));
        if (goreader_reply == NULL) {
            printf("reply DataReader narrow error\n");
            MyDataReaders.ensure_length(0,0);
            subscriber->end_access();
            return;
        }

        // group ordered access, assume if you receive on_data_available,
        // then all have data
        // in any case, if you 'continue' out of this loop early, the
        // untaken samples after may interfere with follow on reads?
        msgRetcode = goreader_msg->take_next_sample(msgData, msgInfo);
        cmdRetcode = goreader_cmd->take_next_sample(cmdData, cmdInfo);
        replyRetcode = goreader_reply->take_next_sample(replyData, replyInfo);

        if (msgRetcode == DDS_RETCODE_NO_DATA) {
            continue;
        } else if (msgRetcode != DDS_RETCODE_OK) {
            printf("msg: take error %d\n", msgRetcode);
            continue;
        }

        if (cmdRetcode == DDS_RETCODE_NO_DATA) {
            printf("cmd: msg has, but cmd does not have, data?\n", cmdRetcode);
            continue;
        } else if (cmdRetcode != DDS_RETCODE_OK) {
            printf("cmd: take error %d\n", cmdRetcode);
            continue;
        }

        if (replyRetcode == DDS_RETCODE_NO_DATA) {
            printf("reply: msg,cmd have, but reply does not have, data?\n", cmdRetcode);
            continue;
        } else if (replyRetcode != DDS_RETCODE_OK) {
            printf("reply: take error %d\n", replyRetcode);
            continue;
        }

        /* Print data sample */
        if (msgInfo.valid_data) {
            bite_msg_tTypeSupport::print_data(&msgData);
        }
        if (cmdInfo.valid_data) {
            bite_iam_cmd_tTypeSupport::print_data(&cmdData);
        }
        if (replyInfo.valid_data) {
            bite_iam_reply_tTypeSupport::print_data(&replyData);
        }
    }
    MyDataReaders.ensure_length(0,0);

    subscriber->end_access();

 

I replaced all the index numbers with names so that I wouldn't get confused about what was what.  Can you please inject that snippit into your code and test it.  NOTE: I do not write c or c++ everyday, so I may have added some other errors here and there, you may need to debug the code a bit to get it to compile and/or run.

Although it was a logical error in the code, I don't think the previous comment was the problem.  Can you please supply the output from the run using this rewritten code.

 

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Thank you for your reply. I injected your solution to my code. The out put was like this :

Loop start, i=0

   message: "Hey, I am X"
   bite_id: 0
   msg_class: <00>
   fault_message_code: 0
   nmuber_of_occurrences: 0
   mode: <00>

   message: "Hey, I am Y"
   bite_id: 0
   func_id: 0
   number_of_objects: 0

   message: "Hey, I am Z"
   bite_id: 0
   func_id: 0
ordered_group subscriber sleeping for 4 sec...
Loop start, i=0
DDSDataReaderSeq_get_reference:!assert index out of bounds
Segmentation fault (core dumped)


The iteration number of the Loop is not increased or mybe it is reseted.

I thought that the problem can be the Condition of The Loop, I wanted to know and wrote like this :

for (i = 0; i < MyDataReaders.length(); i= i+3) {
        printf("Sequence of MyDataReaders, Seq=%d\n", MyDataReaders.length());

After that I got this result:

Sequence of MyDataReaders, Seq=3

   message: "Hey, I am X"
   bite_id: 0
   msg_class: <00>
   fault_message_code: 0
   nmuber_of_occurrences: 0
   mode: <00>

   message: "Hey, I am Y"
   bite_id: 0
   func_id: 0
   number_of_objects: 0

   message: "Hey, I am Z"
   bite_id: 0
   func_id: 0
ordered_group subscriber sleeping for 4 sec...
Sequence of MyDataReaders, Seq=1
DDSDataReaderSeq_get_reference:!assert index out of bounds
Segmentation fault (core dumped)

I'm really confused.!!!!!!

 

 

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Except Ordered Group soloution, Is there any other solution to sends different kinds of TYPEs with different kinds of Data Writers and receive all of them on the Subscriber?

Offline
Last seen: 1 year 3 months ago
Joined: 05/23/2013
Posts: 64

I think the reason why the ordered group example uses the "for loop" is that it uses the same type for 3 data readers. However, because you made up 3 different data types and you already have the code for 3 data readers for 3 different data types, I don't think you need the "for loop" anymore.. Would you try it again with removing the loop? 

Thanks,
Kyoungho

Offline
Last seen: 1 year 3 months ago
Joined: 05/23/2013
Posts: 64

Regarding your question about a subscriber for multiple data wirters, you can have a subscriber for multiple readers and writers anywhere regardless of using ordered group QoS. I think the ordered group QoS can be used if you want to guarantee ordering of samples of grouped data writers and data readers. 

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Thank you for your answer, Tomorrow i will check your solution at work. 

By the way, in any solution, the Subscriber should count the number of DataReaders and after that read each one, am i right?

 

Offline
Last seen: 1 year 3 months ago
Joined: 05/23/2013
Posts: 64

I see. For testing purpose, let's use a hard coding way like following for indexing data readers. 

ordered_group_reader = bite_msg_tDataReader::narrow(MyDataReaders.get_at(0));

ordered_group_reader2 = bite_iam_cmd_tDataReader::narrow(MyDataReaders.get_at(1));

ordered_group_reader3 = bite_iam_reply_tDataReader::narrow(MyDataReaders.get_at(2));

 

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

I removed the Loop but i got the same result again:

DDSDataReaderSeq_get_reference:!assert index out of bounds
Segmentation fault (core dumped)

Offline
Last seen: 1 year 3 months ago
Joined: 05/23/2013
Posts: 64

Would you attach your source code (idl file, publisher, subscirber) here if possible? 

Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Here. I've attached. The IDL file also is there.

File Attachments: 
Offline
Last seen: 1 year 3 months ago
Joined: 05/23/2013
Posts: 64

I modified the subscirber code and it works. Please see the attached. I keep the for loop, and add if statement for different typed data readers. 

File Attachments: 
Offline
Last seen: 8 years 12 months ago
Joined: 11/24/2014
Posts: 26

Yes, It works, Thank you so much for your help

Offline
Last seen: 8 years 8 months ago
Joined: 10/01/2015
Posts: 3

Hello,

I am using Deadline, Lifespan, Reliability, Durability, Liveliness, Source Redundancy (Ownership) policies and I am implementing it on a CAN protocol which has a Publisher and a Subscriber. Can anyone please let me know how I can generate timestamps, Time synchronization between Pub/Sub and also Acknowledgement mechanisms I can use in order to implement Reliability and others. Also Source redundancy mechanisms. I will be working with virtual can interfaces for now.