// a simple test for measure the speed of the reading a tag file #include #include #include #include #include #include #include #include #include #include #include // gettimeofday class eventTags { // a dynamic tags class constructed from tags.root file public: // for the purpose of testing, everything is public struct leaf { // a leaf of the ROOT file std::string name; char type; // used by ROOT unsigned begin, end; // location of the values in XX unsigned loc; // location of the values in Xarray unsigned nent; // actual number of entries in Xarray leaf() : type(0), begin(0), end(0), loc(0), nent(0) {}; }; std::vector leaves; // the 9 possibile types of values in a ROOT file, these pointers are // intended to store values of one event unsigned nCC; // number of variables of type C unsigned nBB; unsigned nbb; unsigned nSS; unsigned nss; unsigned nII; unsigned nii; unsigned nFF; unsigned nDD; Char_t *CC; Char_t *BB; UChar_t *bb; Short_t *SS; UShort_t *ss; Int_t *II; UInt_t *ii; Float_t *FF; Double_t *DD; unsigned nent; // number of events in the tags file unsigned nint; // number of variables of type int (B S I) unsigned nuns; // number of variables of type unsigned int (b s i) unsigned nflt; // number of variables of type float unsigned ndbl; // number of variables of type double unsigned nchr; // number of variables of type char (ROOT C) // pointers intended to store all values within a tags.root file // values of each variable is ordered consecutively in Xarray to ease of // exporting to the next stage of operations int *iarray; unsigned int *uarray; float *farray; double *darray; char *sarray; // default constructor assignes everything to zero (NULL) eventTags() : nCC(0), nBB(0), nbb(0), nSS(0), nss(0), nII(0), nii(0), nFF(0), nDD(0), CC(0), BB(0), bb(0), SS(0), ss(0), II(0), ii(0), FF(0), DD(0), iarray(0), uarray(0), farray(0), darray(0), sarray(0), nent(0), nint(0), nuns(0), nflt(0), ndbl(0), nchr(0) {}; ~eventTags() { delete CC; delete BB; delete bb; delete SS; delete ss; delete II; delete ii; delete FF; delete DD; delete iarray; delete uarray; delete farray; delete darray; delete sarray; } }; // class eventTags class tagValues { public: enum DATA_TYPE {RID=0, FID, INT, UINT, FLOAT, DOUBLE, KEY, STRING}; DATA_TYPE type; tagValues(DATA_TYPE t) : type(t) {} virtual ~tagValues() {}; }; class tagInt : public tagValues { public: std::vector value; tagInt() : tagValues(INT) {}; virtual ~tagInt() {}; }; class tagUInt : public tagValues { public: std::vector value; tagUInt() : tagValues(UINT) {}; virtual ~tagUInt() {}; }; class tagFloat : public tagValues { public: std::vector value; tagFloat() : tagValues(FLOAT) {}; virtual ~tagFloat() {}; }; class tagDouble : public tagValues { public: std::vector value; tagDouble() : tagValues(DOUBLE) {}; virtual ~tagDouble() {}; }; // push strings together into null-terminated list of char class tagString : public tagValues { public: std::vector value; tagString() : tagValues(STRING) {}; virtual ~tagString() {}; }; typedef std::map tagStore; // read the content of a tags.root file one event at a time // returns the number of events read long readEvent(const char* tagsfile) { long cnt = 0; long nerr = 0; TFile tf(tagsfile); TTree *tt = reinterpret_cast(tf.Get("Tag")); if (tt == 0) return cnt; eventTags tags; tags.nent = static_cast(tt->GetEntries()); if (tags.nent < 5) { // very likely something is wrong printf("tag file \"%s\" is very likely to be a " "bad fie, it contains %u entr%s\n", tagsfile, tags.nent, (tags.nent>1 ? "ies" : "y")); return cnt; } else printf("tag file \"%s\" contains %u entries\n", tagsfile, tags.nent); TObjArray *leaves = tt->GetListOfLeaves(); unsigned nLeaves = static_cast(leaves->GetEntriesFast()); if (nLeaves < 5) { fprintf(stderr, "tag file \"%s\" is very likely to be a " "bad fie, it contains %u lea%s\n", tagsfile, nLeaves, (nLeaves>1 ? "ves" : "f")); return cnt; } std::vector sleaf; tags.leaves.resize(nLeaves); // go through leaves to fill the various location arrays (XX) for (unsigned ilv = 0; ilv < nLeaves; ++ ilv) { TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(ilv); unsigned ndim = leaf->GetNdata(); const char *lname = leaf->GetName(); tags.leaves[ilv].name = lname; // no delimiter '.' tags.leaves[ilv].type = leaf->GetTypeName()[0]; switch (tags.leaves[ilv].type) { case 'C': tags.leaves[ilv].loc = tags.nCC * tags.nent; tags.leaves[ilv].begin = tags.nCC; tags.leaves[ilv].end = tags.nCC + ndim; tags.nCC += ndim; sleaf.push_back(&(tags.leaves[ilv])); tags.leaves[ilv].nent = tags.leaves[ilv].loc; break; case 'B': tags.leaves[ilv].begin = tags.nBB; tags.leaves[ilv].end = tags.nBB + ndim; tags.nBB += ndim; break; case 'b': tags.leaves[ilv].begin = tags.nbb; tags.leaves[ilv].end = tags.nbb + ndim; tags.nbb += ndim; break; case 'S': tags.leaves[ilv].begin = tags.nSS; tags.leaves[ilv].end = tags.nSS + ndim; tags.nSS += ndim; break; case 's': tags.leaves[ilv].begin = tags.nss; tags.leaves[ilv].end = tags.nss + ndim; tags.nss += ndim; break; case 'I': tags.leaves[ilv].begin = tags.nII; tags.leaves[ilv].end = tags.nII + ndim; tags.nII += ndim; break; case 'i': tags.leaves[ilv].begin = tags.nii; tags.leaves[ilv].end = tags.nii + ndim; tags.nii += ndim; break; case 'f': case 'F': tags.leaves[ilv].begin = tags.nFF; tags.leaves[ilv].end = tags.nFF + ndim; tags.nFF += ndim; break; case 'd': case 'D': tags.leaves[ilv].begin = tags.nDD; tags.leaves[ilv].end = tags.nDD + ndim; tags.nDD += ndim; break; default: fprintf(stderr, "tag file \"%s\" contains unknown " "data type %s for leaf %s:%s\n", tagsfile, leaf->GetTypeName(), leaf->GetName(), leaf->GetTitle()); ++ nerr; break; } } // for locations in XX if (nerr != 0) { fprintf(stderr, "unable to parse the leaves of \"%s\", nerr=%u", tagsfile, nerr); return cnt; } // compute the sizes for Xarray tags.nint = tags.nBB + tags.nSS + tags.nII; tags.nuns = tags.nbb + tags.nss + tags.nii; tags.nflt = tags.nFF; tags.ndbl = tags.nDD; tags.nchr = sleaf.size(); // allocate memory for all pointer in tags if (tags.nCC) { tags.CC = new Char_t[tags.nCC]; nerr += (tags.CC == 0); } if (tags.nBB) { tags.BB = new Char_t[tags.nBB]; nerr += (tags.BB == 0); } if (tags.nbb) { tags.bb = new UChar_t[tags.nbb]; nerr += (tags.bb == 0); } if (tags.nSS) { tags.SS = new Short_t[tags.nSS]; nerr += (tags.SS == 0); } if (tags.nss) { tags.ss = new UShort_t[tags.nss]; nerr += (tags.ss == 0); } if (tags.nII) { tags.II = new Int_t[tags.nII]; nerr += (tags.II == 0); } if (tags.nii) { tags.ii = new UInt_t[tags.nii]; nerr += (tags.ii == 0); } if (tags.nFF) { tags.FF = new Float_t[tags.nFF]; nerr += (tags.FF == 0); } if (tags.nDD) { tags.DD = new Double_t[tags.nDD]; nerr += (tags.DD == 0); } if (tags.nint) { tags.iarray = new int[tags.nint * tags.nent]; nerr += (tags.iarray == 0); } if (tags.nuns) { tags.uarray = new unsigned int[tags.nuns * tags.nent]; nerr += (tags.uarray == 0); } if (tags.nflt) { tags.farray = new float[tags.nflt * tags.nent]; nerr += (tags.iarray == 0); } if (tags.ndbl) { tags.darray = new double[tags.ndbl * tags.nent]; nerr += (tags.darray == 0); } if (tags.nchr) { tags.sarray = new char[tags.nCC * tags.nent]; nerr += (tags.sarray == 0); } if (nerr != 0) { fprintf(stderr, "unable to allocate memory for the content of " "\"%s\", nerr=%u", tagsfile, nerr); return cnt; } // for loop to assign the locations in Xarray // associate address of each ROOT branch with an address in XX for (unsigned ilv = 0; ilv < nLeaves; ++ ilv) { TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(ilv); const char *bname = leaf->GetBranch()->GetName(); switch (tags.leaves[ilv].type) { case 'C': // loc has been assigned already tt->SetBranchAddress(bname, reinterpret_cast (tags.CC+tags.leaves[ilv].begin)); break; case 'B': // comes after all variables of type I and S tt->SetBranchAddress(bname, reinterpret_cast (tags.BB+tags.leaves[ilv].begin)); tags.leaves[ilv].loc = tags.nent * (tags.leaves[ilv].begin + tags.nII + tags.nSS); break; case 'b': // comes after all variables of type i and s tt->SetBranchAddress(bname, reinterpret_cast (tags.bb+tags.leaves[ilv].begin)); tags.leaves[ilv].loc = tags.nent * (tags.leaves[ilv].begin + tags.nii + tags.nss); break; case 'S': // comes after all variable of type I tt->SetBranchAddress(bname, reinterpret_cast (tags.SS+tags.leaves[ilv].begin)); tags.leaves[ilv].loc = tags.nent * (tags.leaves[ilv].begin + tags.nII); break; case 's': // comes after all variables of type i tt->SetBranchAddress(bname, reinterpret_cast (tags.ss+tags.leaves[ilv].begin)); tags.leaves[ilv].loc = tags.nent * (tags.leaves[ilv].begin + tags.nii); break; case 'I': tt->SetBranchAddress(bname, reinterpret_cast (tags.II+tags.leaves[ilv].begin)); tags.leaves[ilv].loc = tags.nent * tags.leaves[ilv].begin; break; case 'i': tt->SetBranchAddress(bname, reinterpret_cast (tags.ii+tags.leaves[ilv].begin)); tags.leaves[ilv].loc = tags.nent * tags.leaves[ilv].begin; break; case 'f': case 'F': tt->SetBranchAddress(bname, reinterpret_cast (tags.FF+tags.leaves[ilv].begin)); tags.leaves[ilv].loc = tags.nent * tags.leaves[ilv].begin; break; case 'd': case 'D': tt->SetBranchAddress(bname, reinterpret_cast (tags.DD+tags.leaves[ilv].begin)); tags.leaves[ilv].loc = tags.nent * tags.leaves[ilv].begin; break; default: tags.leaves[ilv].loc = tags.nent * tags.leaves[ilv].begin; break; } } // for locations in Xarray // loop over all events for (unsigned ie = 0; ie < tags.nent; ++ ie) { tt->GetEntry(ie, 1); // get all branches // copy from XX to Xarray for (unsigned i = 0; i < tags.nDD; ++ i) { tags.darray[i*tags.nent+ie] = tags.DD[i]; } for (unsigned i = 0; i < tags.nFF; ++ i) { tags.farray[i*tags.nent+ie] = tags.FF[i]; } // three types of integers are folded together into one for (unsigned i = 0; i < tags.nII; ++ i) { tags.iarray[i*tags.nent+ie] = tags.II[i]; } for (unsigned i = 0; i < tags.nii; ++ i) { tags.uarray[i*tags.nent+ie] = tags.ii[i]; } for (unsigned i = 0; i < tags.nSS; ++ i) { tags.iarray[(i+tags.nII)*tags.nent+ie] = tags.SS[i]; } for (unsigned i = 0; i < tags.nss; ++ i) { tags.uarray[(i+tags.nii)*tags.nent+ie] = tags.ss[i]; } for (unsigned i = 0; i < tags.nBB; ++ i) { tags.iarray[(i+tags.nII+tags.nSS)*tags.nent+ie] = tags.BB[i]; } for (unsigned i = 0; i < tags.nbb; ++ i) { tags.uarray[(i+tags.nii+tags.nss)*tags.nent+ie] = tags.bb[i]; } // character strings, only copy one NULL (0) character for each event for (unsigned j = 0; j < tags.nchr; ++ j) { for (unsigned i = sleaf[j]->begin; i < sleaf[j]->end && tags.CC[i] != 0; ++ i) { tags.sarray[sleaf[j]->nent] = tags.CC[i]; ++ (sleaf[j]->nent); } tags.sarray[sleaf[j]->nent] = static_cast(0); ++ (sleaf[j]->nent); } } // for events // assign nent for each leaf for (unsigned ilv = 0; ilv < nLeaves; ++ ilv) { if (tags.leaves[ilv].type == 'C') { tags.leaves[ilv].nent -= tags.leaves[ilv].loc; } else { tags.leaves[ilv].nent = tags.nent; } } } // readEvent // read the content of a tags.root file one branch at a time // returns the number of events read long readBranch(const char* tagsfile) { long cnt = 0; TFile tf(tagsfile); TTree *tt = reinterpret_cast(tf.Get("Tag")); if (tt == 0) return cnt; unsigned nerr = 0; // number of errors encountered during read // number of entries in the file const unsigned nent = static_cast(tt->GetEntries()); if (nent < 5) { // very likely something is wrong printf("tag file \"%s\" is very likely to be a " "bad fie, it contains %u entr%s\n", tagsfile, nent, (nent>1 ? "ies" : "y")); return cnt; } else printf("tag file \"%s\" contains %u entries\n", tagsfile, nent); tagStore store; TObjArray *leaves = tt->GetListOfLeaves(); unsigned nLeaves = leaves->GetEntriesFast(); if (nLeaves < 5) { fprintf(stderr, "tag file \"%s\" is very likely to be a " "bad fie, it contains %u lea%s\n", tagsfile, nLeaves, (nLeaves>1 ? "ves" : "f")); return cnt; } for (unsigned ilv=0; ilv < nLeaves; ++ ilv) { // for each leaf TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(ilv); unsigned ndim = leaf->GetNdata(); tagValues *tval = 0; const char *lname = leaf->GetName(); const char *tmp = strrchr(lname, '.'); if (tmp) // we only use the portion of the name after the last '.' lname = tmp + 1; switch (leaf->GetTypeName()[0]) { case 'C': // null-terminated string { // a null-terminated string has at most ndim characters tagString *act = new tagString; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); tmp = (const char*)leaf->GetValuePointer(); while (*tmp != 0) { // not the terminator act->value.push_back(*tmp); ++ tmp; } // record the terminator act->value.push_back(static_cast(0)); } tval = act; } break; case 'B': // signed 8-bit integer { tagInt *act = new tagInt; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); const char *ptr = ((char*)leaf->GetValuePointer()); if (ndim > 2) { for (unsigned j = 0; j < ndim; ++ j) act->value.push_back(ptr[j]); } else if (ndim == 2) { act->value.push_back(*ptr); act->value.push_back(ptr[1]); } else { act->value.push_back(*ptr); } } tval = act; } break; case 'S': // signed 16-bit integer { tagInt *act = new tagInt; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); short* ptr = (short*)leaf->GetValuePointer(); if (ndim > 2) { for (unsigned j = 0; j < ndim; ++ j) act->value.push_back(ptr[j]); } else if (ndim == 2) { act->value.push_back(*ptr); act->value.push_back(ptr[1]); } else { act->value.push_back(*ptr); } } tval = act; } break; case 'I': // signed 32-bit integer { tagInt *act = new tagInt; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); int* ptr = (int*)leaf->GetValuePointer(); if (ndim > 2) { for (unsigned j = 0; j < ndim; ++ j) act->value.push_back(ptr[j]); } else if (ndim == 2) { act->value.push_back(*ptr); act->value.push_back(ptr[1]); } else { act->value.push_back(*ptr); } } tval = act; } break; case 'b': // unsigned 8-bit integer { tagUInt *act = new tagUInt; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); char* ptr = (char*)leaf->GetValuePointer(); if (ndim > 2) { for (unsigned j = 0; j < ndim; ++ j) act->value.push_back(ptr[j]); } else if (ndim == 2) { act->value.push_back(*ptr); act->value.push_back(ptr[1]); } else { act->value.push_back(*ptr); } } tval = act; } break; case 's': // unsigned 16-bit integer { tagUInt *act = new tagUInt; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); unsigned short *ptr = (unsigned short*)leaf->GetValuePointer(); if (ndim > 2) { for (unsigned j = 0; j < ndim; ++ j) act->value.push_back(ptr[j]); } else if (ndim == 2) { act->value.push_back(*ptr); act->value.push_back(ptr[1]); } else { act->value.push_back(*ptr); } } tval = act; } break; case 'i': // unsigned 32-bit integer { tagUInt *act = new tagUInt; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); unsigned int *ptr = (unsigned int*)leaf->GetValuePointer(); if (ndim > 2) { for (unsigned j = 0; j < ndim; ++ j) act->value.push_back(ptr[j]); } else if (ndim == 2) { act->value.push_back(*ptr); act->value.push_back(ptr[1]); } else { act->value.push_back(*ptr); } } tval = act; } break; case 'F': // 32-bit floating point number { tagFloat *act = new tagFloat; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); float *ptr = (float*)leaf->GetValuePointer(); if (ndim > 2) { for (unsigned j = 0; j < ndim; ++ j) act->value.push_back(ptr[j]); } else if (ndim == 2) { act->value.push_back(*ptr); act->value.push_back(ptr[1]); } else { act->value.push_back(*ptr); } } tval = act; } break; case 'D': // 64-bit floating point number { tagDouble *act = new tagDouble; act->value.reserve(nent*ndim); for (unsigned i = 0; i < nent; ++ i) { TBranch *br = leaf->GetBranch(); br->GetEntry(i); double *ptr = (double*)leaf->GetValuePointer(); if (ndim > 2) { for (unsigned j = 0; j < ndim; ++ j) act->value.push_back(ptr[j]); } else if (ndim == 2) { act->value.push_back(*ptr); act->value.push_back(ptr[1]); } else { act->value.push_back(*ptr); } } tval = act; } break; default: fprintf(stderr, "tag file \"%s\" contains unknown " "data type %s for leaf %s:%s\n", tagsfile, leaf->GetTypeName(), leaf->GetName(), leaf->GetTitle()); ++ nerr; break; } if (tval) { store[lname] = tval; } else { fprintf(stderr, "unable to read \"%s:%s\"\n", lname, leaf->GetTypeName()); ++ nerr; } } // for (unsigned ilv=0 tf.Close(); // no longer need to have it open if (nerr != 0) { fprintf(stderr, "accumulated %u error%s while reading " "\"%s\", will not write out to disk\n", nerr, (nerr > 1 ? "s" : ""), tagsfile); } return cnt; } // readBranch int main(int argc, char **argv) { struct timeval tv1, tv2; for (int i = 1; i < argc; ++ i) { gettimeofday(&tv1, 0); readBranch(argv[i]); gettimeofday(&tv2, 0); printf("%s: readBranch(%s) took %g sec\n", *argv, argv[i], (tv2.tv_sec + 1e-6*tv2.tv_usec) - (tv1.tv_sec + 1e-6*tv1.tv_usec)); gettimeofday(&tv1, 0); readEvent(argv[i]); gettimeofday(&tv2, 0); printf("%s: readEvent(%s) took %g sec\n", *argv, argv[i], (tv2.tv_sec + 1e-6*tv2.tv_usec) - (tv1.tv_sec + 1e-6*tv1.tv_usec)); } return 0; } // main