Calculator.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/calculator/Calculator.cpp#2 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2004-2009 SQLstream, Inc.
00006 // Copyright (C) 2009-2009 LucidEra, Inc.
00007 //
00008 // This program is free software; you can redistribute it and/or modify it
00009 // under the terms of the GNU General Public License as published by the Free
00010 // Software Foundation; either version 2 of the License, or (at your option)
00011 // any later version approved by The Eigenbase Project.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 #include "fennel/common/CommonPreamble.h"
00023 #include "fennel/calculator/Calculator.h"
00024 #include "fennel/calculator/Instruction.h"
00025 #include "fennel/calculator/CalcAssembler.h"
00026 
00027 #include "boost/format.hpp"
00028 using boost::format;
00029 
00030 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/calculator/Calculator.cpp#2 $");
00031 
00032 Calculator::Calculator(DynamicParamManager* dynamicParamManager) :
00033     mIsUsingAssembler(true),
00034     mIsAssembling(false),
00035     mPDynamicParamManager(dynamicParamManager)
00036 {
00037     init(0,0,0,0,0,0);
00038 }
00039 
00040 
00041 Calculator::Calculator(
00042     DynamicParamManager* dynamicParamManager,
00043     int codeSize, int literalSize, int inputSize,
00044     int outputSize, int localSize, int statusSize) :
00045     mIsUsingAssembler(false),
00046     mIsAssembling(false),
00047     mPDynamicParamManager(dynamicParamManager)
00048 {
00049     init(
00050         codeSize, literalSize, inputSize, outputSize,
00051         localSize, statusSize);
00052 }
00053 
00054 void
00055 Calculator::init(
00056     int codeSize, int literalSize, int inputSize,
00057     int outputSize, int localSize, int statusSize)
00058 {
00059     mCode.reserve(codeSize);
00060     mRegisterRef[RegisterReference::ELiteral].reserve(literalSize);
00061     mRegisterRef[RegisterReference::EInput].reserve(inputSize);
00062     mRegisterRef[RegisterReference::EOutput].reserve(outputSize);
00063     mRegisterRef[RegisterReference::ELocal].reserve(localSize);
00064     mRegisterRef[RegisterReference::EStatus].reserve(statusSize);
00065 
00066     int i;
00067     for (i = RegisterReference::EFirstSet;
00068          i < RegisterReference::ELastSet;
00069          i++) {
00070         // explicitly clear registers. allows detection of rebinding
00071         // local & literal
00072         mRegisterSetBinding[i] = NULL;
00073         // explicitly clear descriptors. allows cleaner destructor
00074         mRegisterSetDescriptor[i] = NULL;
00075     }
00076     // Default is to use output register set by reference.
00077     mOutputRegisterByReference = true;
00078 
00079     // Default is to continue execution after exceptions
00080     mContinueOnException = true;
00081 }
00082 
00083 Calculator::~Calculator()
00084 {
00085     uint i;
00086     for (i = RegisterReference::EFirstSet;
00087          i < RegisterReference::ELastSet;
00088          i++) {
00089         unbind((RegisterReference::ERegisterSet)i);
00090     }
00091 
00092     if (mIsUsingAssembler) {
00093         // Assembler created all these register references, let's delete them
00094         for (i = RegisterReference::EFirstSet;
00095              i < RegisterReference::ELastSet;
00096              i++) {
00097             for (uint reg = 0; reg < mRegisterRef[i].size(); reg++) {
00098                 if (mRegisterRef[i][reg]) {
00099                     delete mRegisterRef[i][reg];
00100                 }
00101             }
00102             mRegisterRef[i].clear();
00103             mRegisterReset.clear();
00104         }
00105 
00106         // Assembler created all these instructions so it's up to us
00107         // to delete them
00108         for (i = 0; i < mCode.size(); i++) {
00109             delete mCode[i];
00110         }
00111         mCode.clear();
00112 
00113         for (i = 0; i < mBuffers.size(); i++) {
00114             delete[] mBuffers[i];
00115         }
00116         mBuffers.clear();
00117     }
00118 }
00119 
00120 void
00121 Calculator::outputRegisterByReference(bool flag)
00122 {
00123     mOutputRegisterByReference = flag;
00124 }
00125 
00126 void
00127 Calculator::assemble(const char *program)
00128 {
00129     assert(mIsUsingAssembler);
00130 
00131     FENNEL_TRACE(
00132         TRACE_FINEST,
00133         "Calculator instructions:" << endl <<
00134         InstructionFactory::signatures());
00135     FENNEL_TRACE(
00136         TRACE_FINEST,
00137         "Calculator extended instructions:" << endl <<
00138         InstructionFactory::extendedSignatures());
00139     FENNEL_TRACE(
00140         TRACE_FINE,
00141         "Calculator assembly = |" << endl
00142         << program << "|" << endl);
00143 
00144     mIsAssembling = true;
00145     CalcAssembler assembler(this);
00146     assembler.assemble(program);
00147     mIsAssembling = false;
00148 }
00149 
00150 void  Calculator::unbind(
00151     RegisterReference::ERegisterSet regset,
00152     bool unbindDescriptor)
00153 {
00154     if (unbindDescriptor && mRegisterSetDescriptor[regset]) {
00155         delete mRegisterSetDescriptor[regset];
00156         mRegisterSetDescriptor[regset] = NULL;
00157     }
00158     if (mRegisterSetBinding[regset]) {
00159         delete mRegisterSetBinding[regset];
00160         mRegisterSetBinding[regset] = NULL;
00161     }
00162 }
00163 
00164 void Calculator::bind(
00165     RegisterReference::ERegisterSet regset,
00166     TupleData* data,
00167     const TupleDescriptor& desc)
00168 {
00169     assert(mIsUsingAssembler ? mIsAssembling : true);
00170     assert(regset < RegisterReference::ELastSet);
00171     assert(data); // Not strictly needed
00172 
00173     // At the moment, do not allow literal and local register sets
00174     // to ever be rebound as they (may) have cached pointers.
00175     // If rebinding these register sets is a required feature, you
00176     // must reset each RegisterReference that points to these
00177     // tuples
00178     assert((regset == RegisterReference::ELiteral) ?
00179            !mRegisterSetBinding[RegisterReference::ELiteral] : true);
00180     assert((regset == RegisterReference::ELocal) ?
00181            !mRegisterSetBinding[RegisterReference::ELocal] : true);
00182 
00183     unbind(regset);
00184     mRegisterSetBinding[regset] = new RegisterSetBinding(data);
00185     mRegisterSetDescriptor[regset] = new TupleDescriptor(desc);
00186 
00187     // cache pointers for local and literal sets only
00188     if (regset == RegisterReference::ELiteral ||
00189         regset == RegisterReference::ELocal) {
00190         for_each(
00191             mRegisterRef[regset].begin(),
00192             mRegisterRef[regset].end(),
00193             mem_fun(&RegisterReference::cachePointer));
00194     }
00195 
00196     // pre-allocate mReset vector to the largest possible value
00197     // trade memory for speed - vector should never have to reallocate
00198     // TODO: This calls reserve twice, which is wasteful, even at startup.
00199     size_t totalResetableRegisters =
00200         mRegisterRef[RegisterReference::ELiteral].size() +
00201         mRegisterRef[RegisterReference::ELocal].size();
00202     mRegisterReset.reserve(totalResetableRegisters);
00203 }
00204 
00205 void Calculator::bind(
00206     TupleData* input, TupleData* output,
00207     bool takeOwnwership, const TupleData* outputWrite)
00208 {
00209     unbind(RegisterReference::EInput, false);
00210     mRegisterSetBinding[RegisterReference::EInput] =
00211         new RegisterSetBinding(input, takeOwnwership);
00212     unbind(RegisterReference::EOutput, false);
00213     if (outputWrite) {
00214         mRegisterSetBinding[RegisterReference::EOutput] =
00215             new RegisterSetBinding(output, outputWrite, takeOwnwership);
00216     } else {
00217         mRegisterSetBinding[RegisterReference::EOutput] =
00218             new RegisterSetBinding(output, takeOwnwership);
00219     }
00220 }
00221 
00222 TupleDescriptor
00223 Calculator::getOutputRegisterDescriptor() const
00224 {
00225     return *(mRegisterSetDescriptor[RegisterReference::EOutput]);
00226 }
00227 
00228 TupleDescriptor
00229 Calculator::getInputRegisterDescriptor() const
00230 {
00231     return *(mRegisterSetDescriptor[RegisterReference::EInput]);
00232 }
00233 
00234 TupleDescriptor
00235 Calculator::getStatusRegisterDescriptor() const
00236 {
00237     return *(mRegisterSetDescriptor[RegisterReference::EStatus]);
00238 }
00239 
00240 TupleData const * const
00241 Calculator::getStatusRegister() const
00242 {
00243     return &(mRegisterSetBinding[RegisterReference::EStatus]->asTupleData());
00244 }
00245 
00246 void Calculator::zeroStatusRegister()
00247 {
00248     if (mRegisterSetDescriptor[RegisterReference::EStatus] != NULL) {
00249         RegisterSetBinding *statusBinding =
00250             mRegisterSetBinding[RegisterReference::EStatus];
00251 
00252         int ncols = statusBinding->asTupleData().size();
00253 
00254         for (int i = 0; i < ncols; i++) {
00255             memset(
00256                 const_cast<PBuffer>((*statusBinding)[i].pData),
00257                 0,
00258                 (*statusBinding)[i].cbData);
00259         }
00260     }
00261 }
00262 
00263 void
00264 Calculator::continueOnException(bool c)
00265 {
00266     mContinueOnException = c;
00267 }
00268 
00269 
00270 void
00271 Calculator::exec()
00272 {
00273     // Clear state from previous execution
00274     mWarnings.clear();
00275 
00276     // reset altered registers
00277     for_each(
00278         mRegisterReset.begin(),
00279         mRegisterReset.end(),
00280         mem_fun(&RegisterReference::cachePointer));
00281     mRegisterReset.clear();    // does not change capacity
00282 
00283 #ifdef DEBUG
00284     ostringstream oss;
00285     TuplePrinter p;
00286     if (isTracingLevel(TRACE_FINEST)) {
00287         oss << "Pre-Exec" << endl << "Output Register: " << endl;
00288         p.print(
00289             oss, getOutputRegisterDescriptor(),
00290             mRegisterSetBinding[RegisterReference::EOutput]->asTupleData());
00291         oss << endl << "Input Register: " << endl;
00292         p.print(
00293             oss, getInputRegisterDescriptor(),
00294             mRegisterSetBinding[RegisterReference::EInput]->asTupleData());
00295         oss << endl << "Status Register: " << endl;
00296         p.print(
00297             oss, getStatusRegisterDescriptor(),
00298             mRegisterSetBinding[RegisterReference::EStatus]->asTupleData());
00299         oss << endl;
00300         trace(TRACE_FINEST, oss.str());
00301     }
00302 #endif
00303 
00304 
00305     TProgramCounter pc = 0, endOfProgram;
00306     endOfProgram = mCode.size();
00307 
00308     while (pc >= 0 && pc < endOfProgram) {
00309         try {
00310 #ifdef DEBUG
00311             int oldpc = pc;
00312             string out;
00313             if (isTracingLevel(TRACE_FINEST)) {
00314                 mCode[oldpc]->describe(out, true);
00315                 FENNEL_TRACE(
00316                     TRACE_FINEST, "BF [" << oldpc << "] " <<  out.c_str());
00317             }
00318 #endif
00319 
00320             mCode[pc]->exec(pc);
00321 
00322 #ifdef DEBUG
00323             if (isTracingLevel(TRACE_FINEST)) {
00324                 mCode[oldpc]->describe(out, true);
00325                 FENNEL_TRACE(
00326                     TRACE_FINEST, "AF [" << oldpc << "] " <<  out.c_str());
00327             }
00328 #endif
00329         } catch (CalcMessage m) {
00330             // each instruction sets pc assuming continued execution
00331             mWarnings.push_back(m);
00332             if (!mContinueOnException) {
00333                 break;
00334             }
00335         }
00336     }
00337 #ifdef DEBUG
00338     if (isTracingLevel(TRACE_FINEST)) {
00339         oss.clear();
00340         oss << "Post-Exec" << endl << "Output Register: " << endl;
00341         p.print(
00342             oss, getOutputRegisterDescriptor(),
00343             mRegisterSetBinding[RegisterReference::EOutput]->asTupleData());
00344         oss << endl << "Input Register: " << endl;
00345         p.print(
00346             oss, getInputRegisterDescriptor(),
00347             mRegisterSetBinding[RegisterReference::EInput]->asTupleData());
00348         oss << endl << "Status Register: " << endl;
00349         p.print(
00350             oss, getStatusRegisterDescriptor(),
00351             mRegisterSetBinding[RegisterReference::EStatus]->asTupleData());
00352         oss << endl << "Warnings: |" << warnings() << "|"<< endl;
00353         trace(TRACE_FINEST, oss.str());
00354     }
00355 #endif
00356 }
00357 
00358 string
00359 Calculator::warnings()
00360 {
00361     string ret;
00362     deque<CalcMessage>::iterator iter = mWarnings.begin(),
00363         end = mWarnings.end();
00364     int i = 0;
00365 
00366     while (iter != end) {
00367         ret += boost::io::str(format("[%d]:PC=%ld Code=") % i % iter->pc);
00368         ret += iter->str;
00369         ret += " ";
00370         iter++;
00371         i++;
00372     }
00373     return ret;
00374 }
00375 
00376 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/calculator/Calculator.cpp#2 $");
00377 
00378 // End Calculator.cpp

Generated on Mon Jun 22 04:00:17 2009 for Fennel by  doxygen 1.5.1