00001
00002
00003
00004
00005
00006
00008
00016
00017
00018
00019 #include <stdlib.h>
00020 #include <errno.h>
00021 #include <sys/types.h>
00022 #include <sys/ipc.h>
00023 #include <sys/msg.h>
00024 #include <sys/wait.h>
00025 #include <unistd.h>
00026 #include <string.h>
00027 #include <iostream>
00028
00029 #include "ac_msgbuf.H"
00030
00031 #define REFERENCE_MODEL 0
00032 #define DUV_MODEL 1
00033 #define AC_ERROR( msg ) cerr<< "ArchC ERROR: " << msg <<'\n'
00034 #define AC_MSG( msg ) cerr<< "ArchC: " << msg <<'\n'
00035
00036
00037
00038 using namespace std;
00039
00040 char ACVersion[] = "0.9-beta";
00041
00042 static const unsigned int AC_MAX_UNMATCHED = 20000;
00043
00044
00045
00046 key_t ref_key, duv_key;
00047 int ref_msqid, duv_msqid;
00048 pid_t ref_pid, duv_pid;
00049 struct msqid_ds ref_info, duv_info;
00050
00051
00052 struct dev_list *ref_devlist = NULL, *duv_devlist = NULL;
00053 struct start_msgbuf ref_sbuf, duv_sbuf;
00054 struct dev_loglist *loglist = NULL;
00055
00056
00057
00058
00059
00060 #ifdef DEBUG
00061 #include <stdarg.h>
00062 inline int dprintf(const char *format, ...)
00063 {
00064 int ret;
00065
00066 va_list args;
00067 va_start(args, format);
00068 ret = vfprintf(stderr, format, args);
00069 va_end(args);
00070 return ret;
00071 }
00072 #else
00073 inline void dprintf(const char *format, ...) {}
00074 #endif
00075
00076
00077 #ifdef DDEBUG
00078 #include <stdarg.h>
00079 inline int ddprintf(const char *format, ...)
00080 {
00081 int ret;
00082
00083 va_list args;
00084 va_start(args, format);
00085 ret = vfprintf(stderr, format, args);
00086 va_end(args);
00087 return ret;
00088 }
00089 #else
00090 inline void ddprintf(const char *format, ...) {}
00091 #endif
00092
00093
00094
00095 void CheckOptions(int model);
00096 void ListInit(struct dev_list** model_devlist, int msqid, start_msgbuf *sbuf );
00097 void CheckListConsistency(void);
00098 void AddLog( long type, change_log log, int device );
00099 void MatchLogs( void);
00100
00101
00102 void DoItOntheFly(void);
00103 void FinishIt(void);
00104 void ChangeDump( struct dev_loglist *pllist );
00105
00106
00107 static void DisplayHelp (){
00108 printf ("==================================================\n");
00109 printf (" This is ArchC Verifier for ArchC version %s\n", ACVersion);
00110 printf ("==================================================\n\n");
00111 printf ("Usage: ac_verifier REF_model DUV_model APP [--ref_args=arguments] [--duv_args=arguments]\n\n");
00112 printf (" Where:\n\n");
00113 printf (" --> \"REF_model\" and \"DUV_model\" stand for the path to the executable files\n");
00114 printf (" of each model respectively.\n\n");
00115 printf (" --> \"APP\" stands for the running application file. You must specify the application \n");
00116 printf (" to be loaded using --load or --load_obj options, like in regular ArchC simulations.\n\n");
00117 printf (" --> \"arguments\" stands for the set of arguments to be passed to the running application. \n");
00118 printf (" It must be specified both for the reference and duv models.\n");
00119 printf (" You may specify different arguments for the two models. Like different names for\n");
00120 printf (" output files that you want to compare after the simulation, for example.\n");
00121 printf ("\n\n");
00122 }
00123
00125
00126
00127
00129 void ABORT(){
00130
00131 cerr << "Aborting co-verification ..." << endl;
00132
00133
00134 if (msgctl(ref_msqid, IPC_RMID, NULL) == -1) {
00135 perror("msgctl");
00136 cerr << "Could not delete Ref model msg queue."<<endl;
00137 }
00138
00139 if (msgctl(duv_msqid, IPC_RMID, NULL) == -1) {
00140 perror("msgctl");
00141 cerr << "Could not delete Ref model msg queue."<<endl;
00142 }
00143
00144 if (kill(ref_pid, 15)== -1) {
00145 perror("kill");
00146 cerr << "Could not terminate Ref model process."<<endl;
00147 }
00148
00149 if (kill(duv_pid, 15)== -1) {
00150 perror("kill");
00151 cerr << "Could not terminate DUV model process."<<endl;
00152 }
00153
00154 exit(1);
00155 }
00156
00157
00159
00160
00161
00163 int main(int argc, char *argv[])
00164 {
00165 char *ref_argv[argc], *duv_argv[argc];
00166 int j,i, nargs;
00167 int ref_status, duv_status;
00168 ++argv, --argc;
00169
00170
00171
00172 if( !argv[0] || !strcmp(argv[0], "--help") || !strcmp(argv[0], "-h")){
00173 DisplayHelp();
00174 return 0;
00175 }
00176
00177
00178
00179
00180
00181 if( argc < 3 ){
00182 AC_ERROR("Invalid number of arguments.");
00183 cerr << " Try running ac_verifier --help for more information." <<endl;
00184 exit(1);
00185 }
00186
00187 if( (strncmp( argv[2], "--load_obj=", 11)) && (strncmp( argv[2], "--load=", 7)) ){
00188 AC_ERROR("Invalid argument! Third argument must be the running application file.");
00189 cerr << " You must use --load or --load_obj options, just as it is done with any ArchC model." <<endl;
00190 cerr << " Try running ac_verifier --help for more information." <<endl;
00191 exit(1);
00192 }
00193
00194
00195
00196
00197 if ((ref_key = ftok(argv[0], 'A')) == -1) {
00198 perror("ftok");
00199 exit(1);
00200 }
00201 dprintf("Reference model queue key: %d\n",ref_key);
00202
00203 if ((duv_key = ftok(argv[1], 'A')) == -1) {
00204 perror("ftok");
00205 exit(1);
00206 }
00207 dprintf("DUV model queue key: %d\n",duv_key);
00208
00209 if ((ref_msqid = msgget(ref_key, 0666 | IPC_CREAT)) == -1) {
00210 perror("msgget");
00211 exit(1);
00212 }
00213
00214 if ((duv_msqid = msgget(duv_key, 0666 | IPC_CREAT)) == -1) {
00215 perror("msgget");
00216 exit(1);
00217 }
00218
00219
00220
00221
00222
00223 ref_argv[0] = (char*) malloc( sizeof(char)*strlen(argv[0])+1 );
00224 duv_argv[0] = (char*) malloc( sizeof(char)*strlen(argv[1])+1 );
00225 ref_argv[1] = (char*) malloc( sizeof(char)*strlen(argv[2])+1 );
00226 duv_argv[1] = (char*) malloc( sizeof(char)*strlen(argv[2])+1 );
00227
00228 ref_argv[0] = strcpy(ref_argv[0],argv[0]);
00229 duv_argv[0] = strcpy(duv_argv[0],argv[1]);
00230 ref_argv[1] = strcpy(ref_argv[1],argv[2]);
00231 duv_argv[1] = strcpy(duv_argv[1],argv[2]);
00232
00233 dprintf("REF: %s running %s\n", ref_argv[0], ref_argv[1]);
00234 dprintf("DUV: %s running %s\n", duv_argv[0], duv_argv[1]);
00235
00236 nargs=argc-3;
00237
00238 if ( !nargs ){
00239 dprintf("Running app has no args\n");
00240 ref_argv[2] = NULL;
00241 duv_argv[2] = NULL;
00242 }
00243
00244 argv+=3;
00245 i=0;
00246 while( i <nargs ){
00247
00248 if( !strncmp( argv[i], "--ref_args=", 11) ){
00249
00250
00251 dprintf("Storing Reference model running app args\n");
00252 ref_argv[2] = (char*)malloc(strlen(argv[i]) - 10);
00253 strcpy(ref_argv[2], argv[i]+11);
00254 i++;
00255 j=3;
00256 dprintf("Storing arg %s\n", ref_argv[2]);
00257
00258 while( (i<nargs) && (strncmp( argv[i], "--duv_args=", 11) )){
00259
00260 ref_argv[j] = (char*)malloc(strlen(argv[i])+1);
00261 strcpy(ref_argv[j], argv[i]);
00262 dprintf("Storing arg %s\n", ref_argv[j]);
00263 i++;
00264 j++;
00265 }
00266 dprintf("Reference running application will receive %d arguments\n", j-2);
00267 ref_argv[j] = NULL;
00268 }
00269
00270 if( !strncmp( argv[i], "--duv_args=", 11) ){
00271
00272
00273 dprintf("Storing DUV model running app args\n");
00274 duv_argv[2] = (char*)malloc(strlen(argv[i]) - 10);
00275 strcpy(duv_argv[2], argv[i]+11);
00276 i++;
00277 j=3;
00278 dprintf("Storing arg %s\n", duv_argv[2]);
00279
00280 while( (i<nargs) && (strncmp( argv[i], "--ref_args=", 11) )){
00281 duv_argv[j] = (char*)malloc(strlen(argv[i])+1);
00282 strcpy(duv_argv[j], argv[i]);
00283 dprintf("Storing arg %s\n", duv_argv[j]);
00284 i++;
00285 j++;
00286 }
00287 dprintf("DUV running application will receive %d arguments\n", j-2);
00288 duv_argv[j] = NULL;
00289 }
00290 }
00291
00292
00293
00294 if( !(ref_pid = fork()) ){
00295 execv(ref_argv[0], " --version 2>refout.tmp");
00296 }
00297 else{
00298 if( !(duv_pid = fork()) ){
00299 execv(duv_argv[0], " --version 2>duvout.tmp");
00300 }
00301 else{
00302
00303 waitpid(ref_pid,&ref_status,0);
00304
00305 CheckOptions( REFERENCE_MODEL );
00306
00307
00308 waitpid(duv_pid,&duv_status,0);
00309
00310 CheckOptions( DUV_MODEL );
00311 }
00312 }
00313
00314
00315
00316
00317
00318
00319 if( !(ref_pid = fork()) ){
00320 execv(ref_argv[0], ref_argv);
00321 }
00322 else{
00323 if( !(duv_pid = fork()) ){
00324 execv(duv_argv[0], duv_argv);
00325 }
00326 else{
00327
00328
00329 dprintf("REFERENCE MODEL QUEUE (%d) INITIALIZATION:\n\n",ref_msqid);
00330 ListInit(&ref_devlist, ref_msqid, (struct start_msgbuf*)&ref_sbuf);
00331 dprintf("DUV MODEL QUEUE (%d) INITIALIZATION:\n\n",duv_msqid);
00332 ListInit(&duv_devlist, duv_msqid, (struct start_msgbuf*)&duv_sbuf);
00333
00334
00335 CheckListConsistency();
00336
00337 DoItOntheFly();
00338
00339 waitpid(ref_pid,&ref_status,0);
00340
00341
00342 if(!WIFEXITED(ref_status)){
00343 cerr << "Reference model returned with error" <<endl;
00344 if(WIFSIGNALED(ref_status))
00345 cerr << "Signal : " << WTERMSIG(ref_status)<<endl;
00346 }
00347
00348 waitpid(duv_pid,&duv_status,0);
00349
00350 if(!WIFEXITED(duv_status)){
00351 cerr << "DUV model returned with error" << endl;
00352 if(WIFSIGNALED(duv_status))
00353 cerr << "Signal : " << WTERMSIG(duv_status)<<endl;
00354 }
00355 }
00356 }
00357
00358
00359 FinishIt();
00360
00361
00362 printf("Co-verification finished.\n");
00363
00364
00365 if (msgctl(ref_msqid, IPC_RMID, NULL) == -1) {
00366 perror("msgctl");
00367 exit(1);
00368 }
00369
00370 if (msgctl(duv_msqid, IPC_RMID, NULL) == -1) {
00371 perror("msgctl");
00372 exit(1);
00373 }
00374
00375 return 0;
00376 }
00377
00378
00380
00381
00382
00383
00384
00386
00388
00389
00390
00391
00392
00393
00394
00395
00396
00398
00399 void ListInit( struct dev_list** model_devlist, int msqid, start_msgbuf *sbuf ){
00400
00401 struct dev_msgbuf dbuf;
00402 struct dev_list *pdevlist;
00403 int i;
00404
00405
00406
00407 if (msgrcv(msqid, sbuf, sizeof(struct start_msgbuf), 0, 0) == -1) {
00408 perror("msgrcv");
00409 ABORT();
00410 }
00411
00412
00413 if( sbuf->mtype != 1 ){
00414 AC_ERROR("Invalid initialization message: expecting type 1 (control), got type " << sbuf->mtype );
00415 ABORT();
00416 }
00417
00418 dprintf("-->Number of devices: %d\n",sbuf->ndevice);
00419
00420
00421 for( i=0; i< sbuf->ndevice;i++){
00422 if (msgrcv(msqid, &dbuf, sizeof(dbuf), 0, 0) == -1) {
00423 perror("msgrcv");
00424 ABORT();
00425 }
00426
00427 if( dbuf.mtype != 2 ){
00428 AC_ERROR("Invalid initialization message: expecting type 2 (device), got type " << dbuf.mtype);
00429 ABORT();
00430 }
00431
00432
00433 pdevlist = new (struct dev_list);
00434 pdevlist->dbuf = dbuf;
00435 pdevlist->next = *model_devlist;
00436 *model_devlist = pdevlist;
00437
00438 dprintf("-->Device (%d) name: %s\n", i+1,pdevlist->dbuf.name);
00439 }
00440
00441 }
00442
00444
00445
00446
00448 void CheckListConsistency( ){
00449
00450 struct dev_list *p1;
00451 struct dev_list *p2;
00452 struct dev_loglist *pll;
00453 unsigned next_type = 2 + ref_sbuf.ndevice;
00454
00455 if( !ref_devlist || !duv_devlist ){
00456 AC_ERROR("Uninitialized device lists.");
00457 ABORT();
00458 }
00459
00460
00461 if( ref_sbuf.ndevice != duv_sbuf.ndevice ){
00462 AC_ERROR("Uninitialized device lists.");
00463 ABORT();
00464 }
00465
00466
00467 for (p1 = ref_devlist; p1; p1=p1->next ){
00468
00469 for( p2 = duv_devlist; p2; p2=p2->next) {
00470 if( !strcmp(p1->dbuf.name,p2->dbuf.name))
00471 break;
00472 }
00473 if( !p2 ){
00474
00475 AC_ERROR("Device lists are not consistent. DUV model does not have a "<< p1->dbuf.name <<" device.");
00476 ABORT();
00477 }
00478
00479
00480 pll = new (struct dev_loglist);
00481 pll->type = next_type--;
00482 strcpy(pll->name, p1->dbuf.name);
00483 pll->next = loglist;
00484 loglist = pll;
00485 dprintf("Adding device list for %s with type %d\n",pll->name,pll->type);
00486 }
00487
00488 dprintf("CheckListConsistency passed successfully.\n");
00489
00490 }
00491
00492
00494
00496 void DoItOntheFly(){
00497
00498 struct log_msgbuf lbuf;
00499 bool ref_finished=0, duv_finished=0;
00500 int ref_status, duv_status;
00501 int i;
00502
00503
00504 while( !ref_finished || !duv_finished ){
00505
00506 if( !ref_finished ){
00507
00508 if (msgctl(ref_msqid, IPC_STAT, &ref_info) == -1) {
00509 perror("msgctl");
00510 ABORT();
00511 }
00512
00513 ddprintf("REF QUEUE INFO:\nr-w: %03o, cbytes= %1u, qnum= %1u, qbytes = %1u\n",
00514 ref_info.msg_perm.mode & 0777, ref_info.msg_cbytes, ref_info.msg_qnum, ref_info.msg_qbytes);
00515
00516 i = ref_info.msg_qnum;
00517
00518
00519 if( !i){
00520 waitpid(ref_pid,&ref_status,WNOHANG);
00521 if(WIFEXITED(ref_status)){
00522 dprintf("Matching logs ... Empty queue! Reference model exited!");
00523 if(WIFSIGNALED(ref_status))
00524 dprintf("Signal :%d ", WTERMSIG(ref_status));
00525 ref_finished = 1;
00526 }
00527 }
00528
00529
00530 while (i) {
00531
00532
00533 if (msgrcv(ref_msqid, &lbuf, sizeof(struct log_msgbuf), 0, 0) == -1) {
00534 perror("msgrcv");
00535 ABORT();
00536 }
00537
00538
00539 if( lbuf.log.time == -1 ){
00540 ref_finished = 1;
00541 dprintf("Reference model has finished\n");
00542 }
00543 else{
00544
00545 AddLog(lbuf.mtype, lbuf.log, 0 );
00546 }
00547 i--;
00548 }
00549 }
00550
00551 if(!duv_finished){
00552
00553
00554 if (msgctl(duv_msqid, IPC_STAT, &duv_info) == -1) {
00555 perror("msgctl");
00556 ABORT();
00557 }
00558
00559 ddprintf("DUV QUEUE INFO:\nr-w: %03o, cbytes= %1u, qnum= %1u, qbytes = %1u\n",
00560 duv_info.msg_perm.mode & 0777, duv_info.msg_cbytes, duv_info.msg_qnum, duv_info.msg_qbytes);
00561
00562 i = duv_info.msg_qnum;
00563
00564 if( !i){
00565 waitpid(duv_pid,&duv_status,WNOHANG);
00566
00567 if(WIFEXITED(duv_status)){
00568 dprintf("Matching logs ... Empty queue! DUV model exited!");
00569 if(WIFSIGNALED(duv_status))
00570 dprintf("Signal : ", WTERMSIG(duv_status));
00571
00572 duv_finished =1;
00573 }
00574 }
00575
00576
00577 while (i) {
00578
00579
00580 if (msgrcv(duv_msqid, &lbuf, sizeof(struct log_msgbuf), 0, 0) == -1) {
00581 perror("msgrcv");
00582 ABORT();
00583 }
00584
00585
00586 if( lbuf.log.time == -1 ){
00587 duv_finished = 1;
00588 dprintf("DUV model has finished\n");
00589 }
00590 else{
00591
00592
00593 AddLog(lbuf.mtype, lbuf.log, 1 );
00594 }
00595 i--;
00596 }
00597 }
00598
00599 MatchLogs();
00600
00601 }
00602 }
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00689
00690
00691
00692
00694 void AddLog( long type, change_log log, int device ){
00695
00696 struct dev_loglist *pllist;
00697
00698
00699 for( pllist = loglist; pllist; pllist=pllist->next){
00700
00701 if( type == pllist->type ){
00702
00703 if( device )
00704 pllist->duv_log.push_back(log);
00705 else
00706 pllist->ref_log.push_back(log);
00707
00708 break;
00709 }
00710 }
00711
00712 if( !pllist )
00713 AC_ERROR("Invalid type ("<<type<<") in log message. Update ignored");
00714
00715 }
00716
00717
00719
00721 void MatchLogs( ){
00722
00723 struct dev_loglist *pllist;
00724 log_list::iterator refitor;
00725 log_list::iterator duvitor;
00726 bool flag,error=0;
00727
00728 for( pllist = loglist; pllist; pllist=pllist->next){
00729
00730 if( pllist->duv_log.size() && pllist->ref_log.size()){
00731
00732 pllist->duv_log.sort();
00733 pllist->ref_log.sort();
00734 ddprintf("BEFORE MATCHING...\n");
00735 ddprintf("Device %s -> Log size: %d ref and %d duv\n", pllist->name, pllist->ref_log.size(), pllist->duv_log.size());
00736
00737 #ifdef DDEBUG
00738 ChangeDump( pllist);
00739 #endif
00740 refitor = pllist->ref_log.begin();
00741 while( refitor != pllist->ref_log.end() ){
00742
00743 duvitor = pllist->duv_log.begin();
00744 flag = false;
00745
00746 while( (duvitor != pllist->duv_log.end())){
00747 if( refitor->addr == duvitor->addr &&
00748 refitor->value == duvitor->value ){
00749
00750 refitor = pllist->ref_log.erase( refitor );
00751 duvitor = pllist->duv_log.erase( duvitor );
00752 flag = true;
00753 break;
00754 }
00755 duvitor++;
00756 }
00757
00758 if(!flag)
00759 refitor++;
00760 }
00761
00762 ddprintf("AFTER MATCHING...\n");
00763 ddprintf("Device %s -> Log size: %d ref and %d duv\n", pllist->name, pllist->ref_log.size(), pllist->duv_log.size());
00764
00765 if( pllist->ref_log.size() >= AC_MAX_UNMATCHED || pllist->duv_log.size() >= AC_MAX_UNMATCHED )
00766 error = 1;
00767 }
00768 }
00769 if(error){
00770 dprintf("Too many erros founded. Aborting ...\n");
00771 FinishIt();
00772 ABORT();
00773 }
00774 }
00775
00776
00778
00780 void FinishIt(){
00781
00782 struct dev_loglist *pllist;
00783
00784 for( pllist = loglist; pllist; pllist=pllist->next){
00785
00786 if( pllist->duv_log.size() || pllist->ref_log.size()){
00787
00788 AC_ERROR("Co-verification FAILED. Reference and DUV models have inconsistent update logs for device "<< pllist->name);
00789 cerr <<endl;
00790 ChangeDump( pllist );
00791 }
00792 }
00793 }
00794
00796
00797
00799 void ChangeDump( struct dev_loglist *pllist ) {
00800
00801 log_list::iterator itor;
00802
00803
00804 if( pllist->ref_log.size() ){
00805 cerr <<endl << endl;
00806 cerr << "**************** ArchC Change log *****************\n";
00807 cerr << "* Reference Model Device: "<< pllist->name << endl;
00808 cerr << "***************************************************\n";
00809 cerr << "* Address Value Time *\n";
00810 cerr << "***************************************************\n";
00811
00812 for( itor = pllist->ref_log.begin(); itor != pllist->ref_log.end(); itor++)
00813 cerr << "* " << *itor << " *" << endl;
00814
00815 cerr << "***************************************************\n";
00816 }
00817
00818 if( pllist->duv_log.size() ){
00819 cerr <<endl << endl;
00820 cerr << "**************** ArchC Change log *****************\n";
00821 cerr << "* DUV Model Device: "<< pllist->name << endl;
00822 cerr << "***************************************************\n";
00823 cerr << "* Address Value Time *\n";
00824 cerr << "***************************************************\n";
00825
00826 for( itor = pllist->duv_log.begin(); itor != pllist->duv_log.end(); itor++)
00827 cerr << "* " << *itor << " *" << endl;
00828
00829 cerr << "***************************************************\n";
00830 }
00831
00832 }
00833
00835
00836
00837
00839 void CheckOptions( int model ) {
00840
00841 ifstream input;
00842 string read;
00843 char *filename;
00844 char* p;
00845 bool erro;
00846
00847 if(model == REFERENCE_MODEL)
00848 filename = "refout.tmp";
00849 else
00850 filename = "duvout.tmp";
00851
00852 input.open(filename);
00853
00854 if(!input){
00855 AC_ERROR("Could not open input file: " << filename);
00856 AC_ERROR("Command-line option checker aborted.");
00857 exit(1);
00858 }
00859
00860 getline(input, read);
00861 if( p = strstr( read.c_str(), "(")){
00862
00863 if( strstr( p, "-v") ||strstr( p, "-v)") )
00864 return;
00865 }
00866
00867
00868 if(model == REFERENCE_MODEL)
00869 AC_ERROR("Reference Model is not prepared for co-verification.\n");
00870 else
00871 AC_ERROR("DUV Model is not prepared for co-verification.\n");
00872
00873 AC_MSG(" Run acpp with the -v option for generating models on co-verification mode");
00874 exit(1);
00875
00876 }