/* .External */ SEXP ocl_call(SEXP args) { struct arg_chain *float_args = 0; ocl_call_context_t *occ; int on, an = 0, ftype = FT_DOUBLE, ftsize, ftres, async; SEXP ker = CADR(args), olen, arg, res, octx, dimVec; cl_kernel kernel = getKernel(ker); cl_context context; cl_command_queue commands; cl_device_id device_id = getDeviceID(getAttrib(ker, Rf_install("device"))); cl_mem output; size_t wdims[3] = {0, 0, 0}; int wdim = 1; if (clGetKernelInfo(kernel, CL_KERNEL_CONTEXT, sizeof(context), &context, NULL) != CL_SUCCESS || !context) Rf_error("cannot obtain kernel context via clGetKernelInfo"); args = CDDR(args); res = Rf_getAttrib(ker, install("precision")); if (TYPEOF(res) == STRSXP && LENGTH(res) == 1 && CHAR(STRING_ELT(res, 0))[0] != 'd') ftype = FT_SINGLE; ftsize = (ftype == FT_DOUBLE) ? sizeof(double) : sizeof(float); olen = CAR(args); /* size */ args = CDR(args); on = Rf_asInteger(olen); if (on < 0) Rf_error("invalid output length"); ftres = (Rf_asInteger(CAR(args)) == 1) ? 1 : 0; /* native.result */ if (ftype != FT_SINGLE) ftres = 0; args = CDR(args); async = (Rf_asInteger(CAR(args)) == 1) ? 0 : 1; /* wait */ args = CDR(args); dimVec = coerceVector(CAR(args), INTSXP); /* dim */ wdim = LENGTH(dimVec); if (wdim > 3) Rf_error("OpenCL standard only supports up to three work item dimensions - use index vectors for higher dimensions"); if (wdim) { int i; /* we don't use memcpy in case int and size_t are different */ for (i = 0; i < wdim; i++) wdims[i] = INTEGER(dimVec)[i]; } if (wdim < 1 || wdims[0] < 1 || (wdim > 1 && wdims[1] < 1) || (wdim > 2 && wdims[2] < 1)) Rf_error("invalid dimensions - muse be a numeric vector with positive values"); args = CDR(args); occ = (ocl_call_context_t*) calloc(1, sizeof(ocl_call_context_t)); if (!occ) Rf_error("unable to allocate ocl_call context"); octx = PROTECT(R_MakeExternalPtr(occ, R_NilValue, R_NilValue)); R_RegisterCFinalizerEx(octx, ocl_call_context_fin, TRUE); occ->output = output = clCreateBuffer(context, CL_MEM_WRITE_ONLY, ftsize * on, NULL, &last_ocl_error); if (!output) Rf_error("failed to create output buffer of %d elements via clCreateBuffer (%d)", on, last_ocl_error); if (clSetKernelArg(kernel, an++, sizeof(cl_mem), &output) != CL_SUCCESS) Rf_error("failed to set first kernel argument as output in clSetKernelArg"); if (clSetKernelArg(kernel, an++, sizeof(on), &on) != CL_SUCCESS) Rf_error("failed to set second kernel argument as output length in clSetKernelArg"); occ->commands = commands = clCreateCommandQueue(context, device_id, 0, &last_ocl_error); if (!commands) ocl_err("clCreateCommandQueue"); if (ftype == FT_SINGLE) /* need conversions, create floats buffer */ occ->float_args = float_args = arg_alloc(0, 32); while ((arg = CAR(args)) != R_NilValue) { int n, ndiv = 1; void *ptr; size_t al; switch (TYPEOF(arg)) { case REALSXP: if (ftype == FT_SINGLE) { int i; float *f; double *d = REAL(arg); n = LENGTH(arg); f = (float*) malloc(sizeof(float) * n); if (!f) Rf_error("unable to allocate temporary single-precision memory for conversion from a double-precision argument vector of length %d", n); for (i = 0; i < n; i++) f[i] = d[i]; ptr = f; al = sizeof(float); arg_add(float_args, ptr); } else { ptr = REAL(arg); al = sizeof(double); } break; case INTSXP: ptr = INTEGER(arg); al = sizeof(int); break; case LGLSXP: ptr = LOGICAL(arg); al = sizeof(int); break; case RAWSXP: if (inherits(arg, "clFloat")) { ptr = RAW(arg); ndiv = al = sizeof(float); break; } default: Rf_error("only numeric or logical kernel arguments are supported"); /* no-ops but needed to make the compiler happy */ ptr = 0; al = 0; } n = LENGTH(arg); if (ndiv != 1) n /= ndiv; if (n == 1) {/* scalar */ if ((last_ocl_error = clSetKernelArg(kernel, an++, al, ptr)) != CL_SUCCESS) Rf_error("Failed to set scalar kernel argument %d (size=%d, error code %d)", an, al, last_ocl_error); } else { cl_mem input = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, al * n, ptr, &last_ocl_error); if (!input) Rf_error("Unable to create buffer (%d elements, %d bytes each) for vector argument %d (oclError %d)", n, al, an, last_ocl_error); if (!occ->mem_objects) occ->mem_objects = arg_alloc(0, 32); arg_add(occ->mem_objects, input); #if 0 /* we used this before CL_MEM_USE_HOST_PTR */ if ((last_ocl_error = clEnqueueWriteBuffer(commands, input, CL_TRUE, 0, al * n, ptr, 0, NULL, NULL)) != CL_SUCCESS) Rf_error("Failed to transfer data (%d elements) for vector argument %d (oclError %d)", n, an, last_ocl_error); #endif if ((last_ocl_error = clSetKernelArg(kernel, an++, sizeof(cl_mem), &input)) != CL_SUCCESS) Rf_error("Failed to set vector kernel argument %d (size=%d, length=%d, error %d)", an, al, n, last_ocl_error); /* clReleaseMemObject(input); */ } args = CDR(args); } if ((last_ocl_error = clEnqueueNDRangeKernel(commands, kernel, wdim, NULL, wdims, NULL, 0, NULL, async ? &occ->event : NULL)) != CL_SUCCESS) ocl_err("Kernel execution"); if (async) { /* asynchronous call -> get out and return the context */ #if USE_OCL_COMPLETE_CALLBACK last_ocl_error = clSetEventCallback(occ->event, CL_COMPLETE, ocl_complete_callback, occ); #endif clFlush(commands); /* the specs don't guarantee execution unless clFlush is called */ occ->ftres = ftres; occ->ftype = ftype; occ->on = on; Rf_setAttrib(octx, R_ClassSymbol, mkString("clCallContext")); UNPROTECT(1); return octx; } clFinish(commands); occ->finished = 1; /* we can release input memory objects now */ if (occ->mem_objects) { arg_free(occ->mem_objects, (afin_t) clReleaseMemObject); occ->mem_objects = 0; } if (float_args) { arg_free(float_args, 0); float_args = occ->float_args = 0; } res = ftres ? Rf_allocVector(RAWSXP, on * sizeof(float)) : Rf_allocVector(REALSXP, on); if (ftype == FT_SINGLE) { if (ftres) { if ((last_ocl_error = clEnqueueReadBuffer( commands, output, CL_TRUE, 0, sizeof(float) * on, RAW(res), 0, NULL, NULL )) != CL_SUCCESS) Rf_error("Unable to transfer result vector (%d float elements, oclError %d)", on, last_ocl_error); PROTECT(res); Rf_setAttrib(res, R_ClassSymbol, mkString("clFloat")); UNPROTECT(1); } else { /* float - need a temporary buffer */ float *fr = (float*) malloc(sizeof(float) * on); double *r = REAL(res); int i; if (!fr) Rf_error("unable to allocate memory for temporary single-precision output buffer"); occ->float_out = fr; if ((last_ocl_error = clEnqueueReadBuffer( commands, output, CL_TRUE, 0, sizeof(float) * on, fr, 0, NULL, NULL )) != CL_SUCCESS) Rf_error("Unable to transfer result vector (%d float elements, oclError %d)", on, last_ocl_error); for (i = 0; i < on; i++) r[i] = fr[i]; } } else if ((last_ocl_error = clEnqueueReadBuffer( commands, output, CL_TRUE, 0, sizeof(double) * on, REAL(res), 0, NULL, NULL )) != CL_SUCCESS) Rf_error("Unable to transfer result vector (%d double elements, oclError %d)", on, last_ocl_error); ocl_call_context_fin(octx); UNPROTECT(1); return res; }
/** * selfTest() depends upon periodic purging. Every call, it will first fill up the database, taking memory snapshots, * then purge, taking more memory snapshots. It creates a number of random data objects, inserts them into the system, * and records current memory usage into a file called 'mem.results', for every interation. It does in the following steps: * * 1. Add, approximately, 20 DO's per second, done every poll period (e.g. 10 seconds, means add 200 for that interval). * * 2. When the number of DO's in the system match the threshold setting, we drop the threshold by the same number * we increased it in step 1. In this case, we decrease it by 20, allowing the memory threshold purger to do its job. * * 3. Repeat step 1. * * 4. Repeat step 2. * * 5. Reset system functions to original defaults. * * This allows the system to approach maximum usage, drop to zero, back to maximum usage, then back to zero. * The file can be parse into a plot showing how much memory is freed. This test works regardless of using * in memory database, the improved all memory database, or disk based database. * * WARNING: We use mallinfo() to determine the amount of memory used and released, as the system does NOT * see any memory freed at all, due to the fact dlmallopt(-1) is set in main.cpp. This tells free to not * return freed memory to the system. Thus, using mallinfo is the only means available to show how much * memory is actually freed to the application (but not to the system). * * */ void CacheStrategyUtility::selfTest() { static int init=0; static float amount_do=0; static int count=0; char countStr[50]; static float threshold_backup; static char *direction; if (!init) { init=1; threshold_backup=db_size_threshold; amount_do=20.0*pollPeriodMs/1000; //20 per second seems reasonable if (amount_do > db_size_threshold/10) { amount_do = db_size_threshold/10; } direction="Start"; } // JM: Start DB purging // JM: Testing code only, to prove it works. Lets do linear testing. struct mallinfo mi=mallinfo(); //Due to file permission difficulties in android, we'll write it as a log HAGGLE_DBG("\nThreshold(%s): %lld/%d -- Used bytes: %d, Free bytes: %d, SQL: %lld\n\n", direction, db_size_threshold,current_num_do, mi.uordblks, mi.fordblks, sqlite3_memory_used()); //send db_size_threshold DO's //init = 1 means send DO's //init = 2 means we are in purging mode if ((init == 1) || (init == 3)) { float upperlimit=current_num_do+amount_do; if (upperlimit > db_size_threshold) { upperlimit = db_size_threshold+1; init++; } if (init ==1) { direction="Up1"; } else if (init == 3) { direction="Up2"; } else { direction="StateChangeFromUp"; } for(int i=current_num_do; i<upperlimit; i++) { DataObjectRef dObj = createDataObject(2); dObj->addAttribute("ContentOriginator", "self"); dObj->addAttribute("ContentType", "DelByRelTTL"); dObj->addAttribute("ContentType2", "DelByAbsTTL"); dObj->addAttribute("purge_by_timestamp", "2000000000"); dObj->addAttribute("purge_after_seconds", "2000000000"); char buffer[1025]; snprintf(buffer, 1024, "%llu", (unsigned long long)time(NULL)); sprintf(countStr, "%d", count++); dObj->addAttribute("ContentCreationTime", buffer); dObj->addAttribute("count", countStr); dObj->calcId(); _handleNewDataObject(dObj); } } else if ((init == 2) || (init == 4)) { //init==2, reduction db_size_threshold -= amount_do; if (db_size_threshold < 0.0) { init++; db_size_threshold=threshold_backup; } if (init == 2) { direction="Down1"; } else if (init == 4) { direction="Down2"; } else { direction="StateChangeFromDown"; } } else { //if (init == 5) //clear seltTest? self_test = false; db_size_threshold=threshold_backup; HAGGLE_DBG("Self Test completed!\n"); //remove any last DO's //write any STAT information getKernel()->shutdown(); //return; } // JM: End testing }
ProtocolEvent ProtocolUDPGeneric::receiveData( void *buf, size_t len, const int flags, size_t *bytes) { *bytes = 0; ProtocolEvent pEvent; ssize_t sbytes; SocketWrapper *receiveSocket = getReadEndOfReceiveSocket(); if (NULL == receiveSocket) { HAGGLE_ERR("%s Could not get receive socket\n", getName()); return PROT_EVENT_ERROR_FATAL; } size_t newLength = len + sizeof(udpmsg_t); void *newBuff = malloc(newLength); bzero(newBuff, newLength); pEvent = receiveSocket->receiveData(newBuff, newLength, flags, &sbytes); if (sbytes < 0 || PROT_EVENT_SUCCESS != pEvent) { HAGGLE_ERR("%s Receive failed\n", getName()); free(newBuff); return PROT_EVENT_ERROR; } *bytes = static_cast<size_t>(sbytes) - sizeof(udpmsg_t); if (*bytes <= 0) { HAGGLE_ERR("%s Receive failed (size was wrong)\n", getName()); free(newBuff); return PROT_EVENT_ERROR; } memcpy(lastReceivedSessionNo, getSessionNoFromMsg((const char *)newBuff), sizeof(DataObjectId_t)); lastReceivedSeqNo = getSeqNoFromMsg((const char *)newBuff); unsigned long rcvSrcIP = getSrcIPFromMsg((const char *)newBuff); //unsigned long rcvDestIP = getDestIPFromMsg((const char *)newBuff); HAGGLE_DBG2("%s Got packet with session no %s, sequence no %d, and size %d\n", getName(), DataObject::idString(lastReceivedSessionNo).c_str(), lastReceivedSeqNo, *bytes); memcpy(buf, (void *)&(((char *)newBuff)[sizeof(udpmsg_t)]), len); free(newBuff); if (rcvSrcIP == srcIP) { HAGGLE_ERR("%s Somehow received our own UDP packet: %d\n", getName(), srcIP); return PROT_EVENT_ERROR; } // MOS: START SETTING PEER NODE Mutex::AutoLocker l(mutex); // MOS if (!peerIface) { HAGGLE_ERR("%s UDP peer interface was null\n", getName()); return PROT_EVENT_ERROR; } // MOS - Protocol.cpp relies on peerNode for debugging NodeRef peer = getKernel()->getNodeStore()->retrieve(peerIface); if(peer) peerNode = peer; if (!peerNode) { peerNode = Node::create(Node::TYPE_UNDEFINED, "Peer node"); if (!peerNode) { HAGGLE_ERR("%s Could not create peer node\n", getName()); return PROT_EVENT_ERROR; } peerNode->addInterface(peerIface); } // MOS: END SETTING PEER NODE return pEvent; }
ProtocolEvent ProtocolUDPGeneric::receiveDataObjectNoControl() { ProtocolEvent pEvent; size_t len; pEvent = receiveData(buffer, bufferSize, MSG_DONTWAIT, &len); if (pEvent != PROT_EVENT_SUCCESS) { return pEvent; } buffer[bufferSize-1] = '\0'; if (len == 0) { HAGGLE_DBG("%s Received zero-length message\n", getName()); return PROT_EVENT_ERROR; } if(lastReceivedSessionNo == lastValidReceivedSessionNo && lastReceivedSeqNo == lastValidReceivedSeqNo) { HAGGLE_DBG("%s Ignoring duplicate message - session no %s sequence no %d\n", getName(), DataObject::idString(lastValidReceivedSessionNo).c_str(), lastReceivedSeqNo); return PROT_EVENT_SUCCESS; } memcpy(lastValidReceivedSessionNo, lastReceivedSessionNo, sizeof(DataObjectId_t)); lastValidReceivedSeqNo = lastReceivedSeqNo; // MOS - fastpath based on session id = data object id if (getKernel()->getThisNode()->getBloomfilter()->has(lastValidReceivedSessionNo)) { HAGGLE_DBG("%s Data object (session no %s) already in bloom filter - no event generated\n", getName(), DataObject::idString(lastValidReceivedSessionNo).c_str()); dataObjectsNotReceived += 1; // MOS return PROT_EVENT_SUCCESS; } // MOS - quickly add to Bloom filter to reduce redundant processing in other procotols getKernel()->getThisNode()->getBloomfilter()->add(lastValidReceivedSessionNo); DataObjectRef dObj = DataObject::create_for_putting(localIface, peerIface, getKernel()->getStoragePath()); if (!dObj) { HAGGLE_DBG("%s Could not create data object\n", getName()); return PROT_EVENT_ERROR; } size_t bytesRemaining = DATAOBJECT_METADATA_PENDING; ssize_t bytesPut = dObj->putData(buffer, len, &bytesRemaining, true); if (bytesPut < 0) { HAGGLE_ERR("%s Could not put data\n", getName()); return PROT_EVENT_ERROR; } if(bytesRemaining != len - bytesPut) { HAGGLE_ERR("%s Received data object not complete - discarding\n", getName()); return PROT_EVENT_ERROR; } HAGGLE_DBG("%s Metadata header received [%s].\n", getName(), dObj->getIdStr()); dObj->setReceiveTime(Timeval::now()); // MOS - the following was happening after posting INCOMING but that distorts the statistics HAGGLE_DBG("%s %ld bytes data received (including header), %ld bytes put\n", getName(), len, bytesPut); dataObjectsIncoming += 1; // MOS if(!dObj->isControlMessage()) dataObjectsIncomingNonControl += 1; // MOS dataObjectBytesIncoming += len; // MOS HAGGLE_DBG("%s Received data object [%s] from node %s\n", getName(), DataObject::idString(dObj).c_str(), peerDescription().c_str()); // MOS - removed interface due to locking issue if (getKernel()->getThisNode()->getBloomfilter()->hasParentDataObject(dObj)) { HAGGLE_DBG("%s Data object [%s] already in bloom filter - no event generated\n", getName(), DataObject::idString(dObj).c_str()); dataObjectsNotReceived += 1; // MOS return PROT_EVENT_SUCCESS; } NodeRef node = Node::create(dObj); if (node && (node == getKernel()->getThisNode())) { HAGGLE_DBG("%s Received own node description, discarding early.\n", getName()); dataObjectsNotReceived += 1; // MOS return PROT_EVENT_SUCCESS; } // MOS - this now happens even before xml parsing // getKernel()->getThisNode()->getBloomfilter()->add(dObj); if(bytesRemaining > 0) { ssize_t bytesPut2 = dObj->putData(buffer + bytesPut, len - bytesPut, &bytesRemaining, false); HAGGLE_DBG("%s processing payload - %ld bytes put\n", getName(), bytesPut2); if (bytesPut2 < 0) { HAGGLE_ERR("%s Could not put data\n", getName()); return PROT_EVENT_ERROR; } if(bytesRemaining != 0) { HAGGLE_ERR("%s Received data object not complete - discarding\n", getName()); return PROT_EVENT_ERROR; } } NodeRef currentPeer; { Mutex::AutoLocker l(mutex); currentPeer = peerNode; } // MOS // Generate first an incoming event to conform with the base Protocol class getKernel()->addEvent(new Event(EVENT_TYPE_DATAOBJECT_INCOMING, dObj, currentPeer)); receiveDataObjectSuccessHook(dObj); // Since there is no data following, we generate the received event immediately // following the incoming one getKernel()->addEvent(new Event(EVENT_TYPE_DATAOBJECT_RECEIVED, dObj, currentPeer)); dataObjectsReceived += 1; // MOS dataObjectBytesReceived += len; // MOS if(dObj->isNodeDescription()) { nodeDescReceived += 1; nodeDescBytesReceived += len; } // MOS return PROT_EVENT_SUCCESS; }
bool ProtocolUDPGeneric::init_derived() { if (!peerIface) { HAGGLE_ERR("%s No peer interface\n", getName()); return false; } if (!localIface) { HAGGLE_ERR("%s No local interface\n", getName()); return false; } SOCKET sockets[2]; if (0 > socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets)) { HAGGLE_ERR("%s Could not create socket pair for receiver: %s\n", getName(), STRERROR(ERRNO)); HAGGLE_ERR("FATAL ERROR - EMERGENCY SHUTDOWN INITIATED\n"); // MOS getKernel()->setFatalError(); getKernel()->shutdown(); return false; } else { HAGGLE_DBG2("%s Opening socketpair (%d,%d)\n", getName(), sockets[0], sockets[1]); } writeEndOfReceiveSocket = new SocketWrapper(getKernel(), getManager(), sockets[0]); if (!writeEndOfReceiveSocket) { HAGGLE_ERR("%s Could not allocate write end\n", getName()); return false; } if (!writeEndOfReceiveSocket->multiplySndBufferSize(2)) { HAGGLE_ERR("%s Could not multiply buffer size.\n", getName()); return false; } readEndOfReceiveSocket = new SocketWrapper(getKernel(), getManager(), sockets[1]); if (!readEndOfReceiveSocket) { HAGGLE_ERR("%s Could not allocate read end\n", getName()); return false; } if (!readEndOfReceiveSocket->multiplyRcvBufferSize(2)) { HAGGLE_ERR("%s Could not multiply buffer size.\n", getName()); return false; } srcIP = interfaceToIP(localIface); if (0 == srcIP) { HAGGLE_ERR("%s Could not get source IP.\n"); return false; } destIP = interfaceToIP(peerIface); if (0 == destIP) { HAGGLE_ERR("%s Could not get dest IP.\n"); return false; } return initbase(); }