MINOS Offline Documentation
[home] [installing MINOS software] [supported platforms] [package links] [mailing list] [HyperNews] [FAQ] [computing help] [MINOS glossary] [archives]

HowTo: the MINOS rotorooter

WHAT IS THE rotorooter?

The rotorooter is a server that accepts buffers of data from the MINOS DAQ (Data Acquisition) or DCS (Detector Control System) or their proxies and turns those buffers into MINOS standard RawRecord objects containing RawDataBlocks. It manages naming, opening and closing the files and the streams (TTrees) within a file.

RUNNING THE rotorooter

The server program is started using the command: rotorooter.
$ rotorooter -h
 usage: rotorooter -a -p<port#> -b<buffersize> -l<syslog> -e
   -a: allow file overwriting
   -p: port number rotorooter is listening on
        or file name    
   -b: initial buffer size in long words
   -l: syslog facility (eg. 'user')
   -e: direct syslog errors to stderr as well
   -d: detector override
   -s: simflag override
   -h: print this message

By default the rotorooter does not allow new output files to overwrite existing files. To override this, for test purposes, one can supply the -a flag and rotorooter will merrily trample over existing files without complaint. Without the flag the rotorooter will create a new filename, e.g. :-
basename.mdaq.root first attempt
basename.1.mdaq.root first overwrite attempt
basename.2.mdaq.root second overwrite attempt

One can set the port number on which the server listens. Thus multiple copies of rotorooter can be running on a given host machine, each listening to a different port. This could be useful if there were one machine on which output root files were to be written, but one wanted different processes handling DAQ and DCS records. The pre-assigned ports are 9011 for DAQ (default) and 9012 for DCS. Alternatively the "port" can be set to an input file name in which case just that one file is processed e.g.:-

$ rotorooter -a -p run1772.dat
and rotorooter will terminate as soon as the file finished. To process a zipped file without first uncompressing, pipe the uncompressed output to rotorooter and set the "port" to /dev/stdin e.g.:-
$ gzip -dc run1772.dat.gz | rotorooter -a -p /dev/stdin

The buffer into which data buffers are read is initialized to a default size. Using the -b flag changes the size of the initial buffer. The buffer handling works by floating to a high water mark: if data is sent to the rotorooter that is larger than the buffer it currently holds then it deletes the current buffer and tries to acquire a buffer large enough to satisfy the request. It never tries to resize the buffer downward. If it can't allocate one large enough it works its way downward in 1K chunks until it gets a good buffer; but in such a case the current record might end up corrupted.

As a server that might not be directly connected to a terminal it is necessary to direct warning and error messages somewhere they can be retrieved. Formatted text messages are sent to the syslog facility. Individual messages have different priorities and the syslogd might redirect or ignore messages depending on these options and the configuration in /etc/syslog.config of the host machine. Using the -l flag one can configure the server to use a different syslog "facility" (these include user, local0 through local7). The default value is "local1". If one wants the messages sent to stderr as well then supply the -e flag on the command line.

STOPPING THE rotorooter

If the rotorooter process has no connection established to a data source process then the command:
$ roto_status -s 0
will cause the server to do a controlled shutdown.
Eventually -s 1 should be capable of forcing the server to disconnect from any attached processes and shut itself down, by this is not yet implemented (see Current limitations below).

Sending (e.g. via kill) either the signal SIGTERM (15) or SIGINT (2) to the rotorooter process will force it to terminate any connection to a data source, cleanly close all streams and files and terminate.


The expected model for sending data to the rotorooter is that the DAQ and DCS systems will use the supplied C code. This code is located in the MINOS offline code distribution in the subdirectory RotoTalk under the Rotorooter package.

Additionally, there is support for converting the straight binary files that the DAQ is capable of writing. In the offline context there is a JobControl module available for taking a RawRecord held by "mom" and sending it to the rotorooter or writing in the binary file format of the pre-rotorooter DAQ.


$ ls $SRT_PUBLIC_CONTEXT/Rotorooter/RotoTalk/rototalk.*
rototalk.c  rototalk.h

The interface function prototypes are declared in rototalk.h and the code for them is in rototalk.c. The second of these relies on two MINOS specific include files:

These include files are only necessary for the compilation of rototalk.c; user code that needs to interface to the library only needs rototalk.h to define the interfaces and the return codes. The offline code repository will have build a static library $SRT_PUBLIC_CONTEXT/lib/<platform>/libRotorooterRotoTalk.a against which users can link their code.

Normal usage establishes a connection to the rotorooter once at the beginning of the job and closes it as it exits. Once a connection is established the process then opens a file, sends a series of records and closes the file as necessary. In the case of the DAQ system it might be necessary to have two files open simultaneously during the transition from one subrun to another -- this is supported by the system.


In order to support the transition from the DAQ writing flat binary files over to using the rotorooter there is a stand alone program for processing the binary files.
$ daq_bin2roto -h
 usage: daq_bin2roto -i<hostname>  -p<port#> -b<buffersize> -w<whoami> -n<maxrec> <filenames..>
   -i: hostname where rotorooter is running
   -b: buffer size to use
   -w: DCP or DCS
   -p: port number rotorooter is listening on
   -v: how verbose to be
   -n: maximum number of records from each file
   -h: print this message


One can use a RotoClientModule in the offline framework to convert the first RawRecord held by mom into a record sent to the rotorooter. An example jcm would look like:
# A simple job to run roto client
# usage: demojob -bqx roto.jcm 
# rhatcher@fnal.gov

# get library loaded
/Root/LoadLibrary libRotorooter

#/Msg/SetLevel Exodus Debug
#/Msg/SetLevel Roto   Debug

# create a path
/Path/Create Roto \
 Input::Get \
 RerootToRawDataModule::Get \

# uncomment next line to write to binary file 
#/Roto/RotoClientModule/Set HostPort mybinaryfile.dat -1
/Roto/RotoClientModule/Set BufferWords 6291456
/Roto/RotoClientModule/Set Primary 1

/Roto/Input/Add root_files/gm_far_cosmic_2_hapr01.root
/Roto/Run Nin 50

Reading the new files in the offline framework

A file of RawRecords can be read in under job control processing using the standard input module (slightly reconfigured).

JobControl SCRIPT

#======================================================================= # # A simple job to read the new RawRecord files # # usage: demojob -bqx read_raw.jcm # # rhatcher@fnal.gov #======================================================================= # load a macro to be run as part of the path # dump_raw.C - takes a "mom" and rummages around in it /Root/LoadMacro dump_raw.C # create a path /Path/Create ReadTest \ Input::Get \ RootCommand::Ana # define when the macro get called and with what arguments # "mom" is the one currently being processed by the path /ReadTest/RootCommand/AddLine/Ana dump_raw(mom,"Ana") # appears SetFormat must happen *before* Add! Don't know why. # eventually code will recognize the standard file extension # and do this automagically /ReadTest/Input/SetFormat raw /ReadTest/Input/Add F00002401_0000.mdaq /ReadTest/Run Nin 20


void rawPrint(RawRecord *rawrec) { if (rawrec == 0) { cout << "No RawRecord found." << endl; return; } bool explicit_iter = true; bool xdump = true; if (explicit_iter) { // Print RawRecord types const RawHeader* rawhead = rawrec->GetRawHeader(); if (rawhead) { cout << " "; rawhead->Print(); } TIter rbi = rawrec->GetRawBlockIter(); RawDataBlock *rb; RawDigitDataBlock *rddb = 0; while ((rb = dynamic_cast<RawDataBlock *>(rbi()))) { cout << " " << rb->ClassName() << ":" << rb->GetName() << endl; if (!rddb) { //not under CINT // rddb = dynamic_cast<RawDigitDataBlock *>(rb); if (rb->InheritsFrom("RawDigitDataBlock")) { // CINT treats dynamic_cast as a straight C cast // and never returns 0 if it isn't the right type rddb = (RawDigitDataBlock *)(rb); } } if (xdump) rb->Print("x"); } } else rawrec->Print(); } void dump_raw(const MomNavigator* mom, char* byWhom) { if (!mom) { cout << "dump_raw had a null mom ... attempt JobCROOT::GetMom()"; // Attach the current mom ... may fail with an assert() JobCROOT& jc = JobCROOT::Instance(); mom = jc.GetMom(); } bool dumpfrag = true; if (dumpfrag) { TIter fitr = const_cast<MomNavigator*>(mom)->FragmentIter(); cout << "List of Fragments in MomNavigator:" << endl; TObject* tobj; int i = 0; while (tobj = (fitr()) ) { cout << " [" << i << "] " << tobj->ClassName() << ": \"" << tobj->GetName() << "\""<< endl; } } // Find RawRecord fragment in MOM. RawRecord *rawrec = dynamic_cast<RawRecord *> (mom->GetFragment("RawRecord")); if (rawrec == 0) { cout << "No RawRecord in MOM, " << "mom is " << mom << endl; return; } rawPrint(rawrec); }


Last Modified: $Date: 2002/12/17 21:32:15 $
Contact: rhatcher@fnal.gov
Page viewed from http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/howto_roto.html
Security, Privacy, Legal Fermi National Accelerator Laboratory