def __init__(self): if sys.platform.startswith("win"): self.dwf = cdll.dwf elif sys.platform.startswith("darwin"): self.dwf = cdll.LoadLibrary( "/Library/Frameworks/dwf.framework/dwf") elif sys.platform.startswith("cygwin"): self.dwf = CDLL("dwf.dll") else: self.dwf = cdll.LoadLibrary("libdwf.so") self.hdwf = c_int() v = create_string_buffer(16) self.dwf.FDwfGetVersion(v) self.dwfversion = v.value self.open() self._vposSetOffset = 0.0 self._vposGetOffset = 0.0 self.vpos = PowerSupply.PowerSupply(self.dwf, self.hdwf, 0) self.vneg = PowerSupply.PowerSupply(self.dwf, self.hdwf, 1) self.fg1 = FunctionGenerator.FunctionGenerator(self.dwf, self.hdwf, 0) self.fg2 = FunctionGenerator.FunctionGenerator(self.dwf, self.hdwf, 1) self.scope = Oscilloscope.Oscilloscope(self.dwf, self.hdwf) self.dwf.FDwfAnalogIOEnableSet(self.hdwf, c_int(True)) self.dwf.FDwfDeviceAutoConfigureSet(self.hdwf, c_int(True))
def test_generateLogFunctions(self): self.maxDiff = None fg = FunctionGenerator() fmtStr = "Hello World! %0u %*.*s %*.19lf %19.*s" ret = fg.generateLogFunctions("ERROR", fmtStr, "testFile.cc", "testFile.cc", 100) logId = generateLogIdStr(fmtStr, "testFile.cc", 100) expectedFnName = "__syang0__fl" + logId expectedResult = ("void " + expectedFnName + "(NanoLog::LogLevel level" ", const char* fmtStr , unsigned int arg0, " "int arg1, int arg2, const char* arg3, " "int arg4, double arg5, " "int arg6, const char* arg7)", expectedFnName) self.assertEqual(expectedResult, ret) self.assertEqual(2, len(fg.logId2Code)) code = fg.logId2Code[logId] self.assertEqual(fmtStr, code["fmtString"]) self.assertEqual("testFile.cc", code["filename"]) self.assertEqual(100, code["linenum"])
def test_outputMappingFile(self): fg = FunctionGenerator() fg.generateLogFunctions("DEBUG", "A", "mar.cc", "mar.cc", 293) fg.generateLogFunctions("DEBUG", "B", "mar.cc", "mar.cc", 294) fg.generateLogFunctions("DEBUG", "C", "mar.cc", "mar.cc", 200) fg.generateLogFunctions("DEBUG", "D %d", "s.cc", "s.cc", 100) # Test serialization and deserialization fg.outputMappingFile("test.json") with open("test.json") as dataFile: data = json.load(dataFile) self.assertEqual(fg.argLists2Cnt, data.get('argLists2Cnt')) self.assertEqual(fg.logId2Code, data.get('logId2Code')) os.remove("test.json")
def test_generateLogFunctions_empty(self): self.maxDiff = None fg = FunctionGenerator() ret = fg.generateLogFunctions("DEBUG", "Empty Print", "gar.cc", "mar.cc", 293) logId = generateLogIdStr("Empty Print", "mar.cc", 293) expectedFnName = "__syang0__fl" + logId expectedResult = ("void " + expectedFnName + "(NanoLog::LogLevel level" ", const char* fmtStr )", expectedFnName) self.assertEqual(expectedResult, ret) code = fg.logId2Code[logId] self.assertEqual("Empty Print", code['fmtString']) self.assertEqual("mar.cc", code["filename"]) self.assertEqual(293, code["linenum"]) self.assertEqual("gar.cc", code["compilationUnit"])
def test_outputMappingFile_withFolders(self): fg = FunctionGenerator() fg.generateLogFunctions("DEBUG", "A", "mar.cc", "mar.cc", 293) fg.generateLogFunctions("DEBUG", "B", "mar.cc", "mar.cc", 294) fg.generateLogFunctions("DEBUG", "C", "mar.cc", "mar.cc", 200) fg.generateLogFunctions("DEBUG", "D %d", "s.cc", "s.cc", 100) # Test what happens when the directory does not exist try: os.remove("testFolder/test.json") os.removedirs("testFolder") except: pass fg.outputMappingFile("testFolder/test.json") with open("testFolder/test.json") as dataFile: data = json.load(dataFile) self.assertEqual(fg.argLists2Cnt, data.get('argLists2Cnt')) self.assertEqual(fg.logId2Code, data.get('logId2Code')) os.remove("testFolder/test.json") os.removedirs("testFolder")
def test_outputCompilationFiles(self): self.maxDiff = None fg = FunctionGenerator() fg.generateLogFunctions("DEBUG", "A", "mar.cc", "mar.cc", 293) fg.generateLogFunctions("DEBUG", "B", "mar.cc", "mar.cc", 294) fg.generateLogFunctions("DEBUG", "C", "mar.cc", "mar.cc", 200) fg.generateLogFunctions("DEBUG", "D %d", "s.cc", "s.cc", 100) fg.generateLogFunctions("DEBUG", "E %4s %*.*lf", "s.cc", "s.cc", 100) fg.outputMappingFile("map1.map") # Also test the merging fg2 = FunctionGenerator() fg2.generateLogFunctions("DEBUG", "A", "mar.cc", "mar.cc", 293) fg2.generateLogFunctions("DEBUG", "A", "mar.cc", "mar.h", 1) fg2.generateLogFunctions("DEBUG", "E", "del.cc", "del.cc", 199) fg2.outputMappingFile("map2.map") # Merge the two map files FunctionGenerator.outputCompilationFiles("test.h", ["map1.map", "map2.map"]) self.assertTrue(filecmp.cmp("test.h", "unitTestData/test_outputCompilationFiles.h")) os.remove("map1.map") os.remove("map2.map") os.remove("test.h")
def test_getRecordFunctionDefinitionsFor(self): self.maxDiff = None emptyRec = \ """ inline void __syang0__fl{logId}(NanoLog::LogLevel level, const char* fmtStr ) {{ extern const uint32_t __fmtId{logId}; if (level > NanoLog::getLogLevel()) return; uint64_t timestamp = PerfUtils::Cycles::rdtsc(); ; size_t allocSize = sizeof(NanoLogInternal::Log::UncompressedEntry); NanoLogInternal::Log::UncompressedEntry *re = reinterpret_cast<NanoLogInternal::Log::UncompressedEntry*>(NanoLogInternal::RuntimeLogger::reserveAlloc(allocSize)); re->fmtId = __fmtId{logId}; re->timestamp = timestamp; re->entrySize = static_cast<uint32_t>(allocSize); char *buffer = re->argData; // Record the non-string arguments %s // Record the strings (if any) at the end of the entry %s // Make the entry visible NanoLogInternal::RuntimeLogger::finishAlloc(allocSize); }} """ % ("", "") fg = FunctionGenerator() fg.generateLogFunctions("DEBUG", "A", "mar.cc", "mar.cc", 293) fg.generateLogFunctions("DEBUG", "B", "mar.cc", "mar.cc", 293) fg.generateLogFunctions("DEBUG", "C", "mar.cc", "mar.cc", 200) fg.generateLogFunctions("DEBUG", "D", "s.cc", "mar.cc", 100) self.assertEqual(3, len(fg.getRecordFunctionDefinitionsFor("mar.cc"))) self.assertEqual(1, len(fg.getRecordFunctionDefinitionsFor("s.cc"))) self.assertEqual(0, len(fg.getRecordFunctionDefinitionsFor("asdf.cc"))) funcs = fg.getRecordFunctionDefinitionsFor("mar.cc") funcs.sort() logId = generateLogIdStr("A", "mar.cc", 293) self.assertMultiLineEqual(emptyRec.format(logId=logId), funcs[0]) logId = generateLogIdStr("B", "mar.cc", 293) self.assertMultiLineEqual(emptyRec.format(logId=logId), funcs[1]) logId = generateLogIdStr("C", "mar.cc", 200) self.assertMultiLineEqual(emptyRec.format(logId=logId), funcs[2]) logId = generateLogIdStr("D", "mar.cc", 100) self.assertMultiLineEqual(emptyRec.format(logId=logId), fg.getRecordFunctionDefinitionsFor("s.cc")[0])
def test_generateLogFunctions_combinationAndOverwrite(self): fg = FunctionGenerator() # TODO(syang0) Currently we do not differenciate on files, only strings. # In the future, please add multi-file support that way the correct # filename and line number are saved # Original fg.generateLogFunctions("DEBUG", "A", "mar.cc", "mar.cc", 293) # Different log fg.generateLogFunctions("DEBUG", "B", "mar.cc", "mar.cc", 293) # Same log + file, different location fg.generateLogFunctions("DEBUG", "A", "mar.cc", "mar.cc", 200) # same log, diff file + location fg.generateLogFunctions("DEBUG", "A", "s.cc", "s.cc", 100) # same log, diff compilation unit, but same originating file fg.generateLogFunctions("DEBUG", "A", "s.cc", "mar.cc", 293) ids = list(fg.logId2Code) ids.sort() self.assertEqual(['__A__mar46cc__200__', '__A__mar46cc__293__', '__A__s46cc__100__', '__B__mar46cc__293__', '__INVALID__INVALID__INVALID__'], ids)
def processFile(inputFile, mapOutputFilename): functionGenerator = FunctionGenerator() directiveRegex = re.compile("^# (\d+) \"(.*)\"(.*)") with open(inputFile) as f, open(inputFile + "i", 'w') as output: try: lines = f.readlines() lineIndex = -1 lastChar = '\0' # Logical location in a file based on GNU Preprocessor directives ppFileName = inputFile ppLineNum = 0 # Notes the first filename referenced by the pre-processor directives # which should be the name of the file being compiled. firstFilename = None # Marks at which line the preprocessor can start safely injecting # generated, inlined code. A value of None indicates that the NanoLog # header was not #include-d yet inlineCodeInjectionLineIndex = None # Scan through the lines of the file parsing the preprocessor directives, # identfying log statements, and replacing them with generated code. while lineIndex < len(lines) - 1: lineIndex = lineIndex + 1 line = lines[lineIndex] # Keep track of of the preprocessor line number so that we can # put in our own line markers as we inject code into the file # and report errors. This line number should correspond to the # actual user source line number. ppLineNum = ppLineNum + 1 # Parse special preprocessor directives that follows the format # '# lineNumber "filename" flags' if line[0] == "#": directive = directiveRegex.match(line) if directive: # -1 since the line num describes the line after it, not the # current one, so we decrement it here before looping ppLineNum = int(float(directive.group(1))) - 1 ppFileName = directive.group(2) if not firstFilename: firstFilename = ppFileName flags = directive.group(3).strip() continue if INJECTION_MARKER in line: inlineCodeInjectionLineIndex = lineIndex continue if ppFileName in ignored_files: continue # Scan for instances of the LOG_FUNCTION using a simple heuristic, # which is to search for the LOG_FUNCTION outside of quotes. This # works because at this point, the file should already be pre-processed # by the C/C++ preprocessor so all the comments have been stripped and # all #define's have been resolved. prevWasEscape = False inQuotes = False charOffset = -1 # Optimization: Make sure line has LOG_FUNCTION before doing more work if LOG_FUNCTION not in line: continue while charOffset < len(line) - 1: charOffset = charOffset + 1 c = line[charOffset] # If escape, we don't really care about the next char if c == "\\" or prevWasEscape: prevWasEscape = not prevWasEscape lastChar = c continue if c == "\"": inQuotes = not inQuotes # If we match the first character, cheat a little and scan forward if c == LOG_FUNCTION[0] and not inQuotes: # Check if we've found the log function via the following heuristics # (a) the next n-1 characters spell out the rest of LOG_FUNCTION # (b) the previous character was not an alpha numeric (i.e. not # a part of a longer identifier name) # (c) the next syntactical character after log function is a ( found = True for ii in range(len(LOG_FUNCTION)): if line[charOffset + ii] != LOG_FUNCTION[ii]: found = False break if not found: continue # Valid identifier characters are [a-zA-Z_][a-zA-Z0-9_]* if lastChar.isalnum() or lastChar == '_': continue # Check that it's a function invocation via the existence of ( filePosAfter = FilePosition( lineIndex, charOffset + len(LOG_FUNCTION)) mChar, mPos = peekNextMeaningfulChar( lines, filePosAfter) if mChar != "(": continue # Okay at this point we are pretty sure we have a genuine # log statement, parse it and start modifying the code! logStatement = parseLogStatement( lines, (lineIndex, charOffset)) lastLogStatementLine = logStatement[ 'semiColonPos'].lineNum if len(logStatement['arguments']) < 2: raise ValueError( "NANO_LOG statement expects at least 2 arguments" ": a LogLevel and a literal format string", lines[lineIndex:lastLogStatementLine + 1]) # We expect the log invocation to have the following format: # LOG_FN(LogLevel, FormatString, ...), hence the magic indexes logLevel = logStatement['arguments'][0].source fmtArg = logStatement['arguments'][1] fmtString = extractCString(fmtArg.source) # At this point, we should check that NanoLog was #include-d # and that the format string was a static string if not inlineCodeInjectionLineIndex: raise ValueError( "NANO_LOG statement occurred before " "#include-ing the NanoLog header!", lines[lineIndex:lastLogStatementLine + 1]) if not fmtString: raise ValueError( "NANO_LOG statement expects a literal format " "string for its second argument", lines[lineIndex:lastLogStatementLine + 1]) # Invoke the FunctionGenerator and if it throws a ValueError, # tack on an extra argument to print out the log function itself try: (recordDecl, recordFn ) = functionGenerator.generateLogFunctions( logLevel, fmtString, firstFilename, ppFileName, ppLineNum) except ValueError as e: raise ValueError( e.args[0], lines[lineIndex:lastLogStatementLine + 1]) # Now we're ready to inject the code. What's going to happen is # that the original LOG_FUNCTION will be ripped out and in its # place, a function invocation for the record logic will be # inserted. It will look something like this: # # input: "++i; LOG("Test, %d", 5); ++i;" # output: "i++; # # 1 "injectedCode.fake" # { # __syang0__fl__( # # 10 "original.cc" # "Test, %d", 5); } # # 10 "original.cc" # ++i;" # # Note that we try to preserve spacing and use line preprocessor # directives wherever we can so that if the compiler reports # errors, then the errors can be consistent with the user's view # of the source file. # First we separate the code that comes after the log statement's # semicolon onto its own line while preserving the line spacing # and symbolic reference to the original source file # # Example: # "functionA(); functionB();" # becomes # "functionA(); # # 10 "filename.cc" # functionB();" # # Note that we're working from back to front so that our line # indices don't shift as we insert new lines. scLineNum, scOffset = logStatement['semiColonPos'] scLine = lines[scLineNum] # Extrapolate the symbolic line number scPPLineNum = ppLineNum + (scLineNum - lineIndex) # Split the line scHeadLine = scLine[:scOffset + 1] + "\r\n" scMarker = "# %d \"%s\"\r\n" % (scPPLineNum, ppFileName) scTailLine = " " * (scOffset + 1) + scLine[scOffset + 1:] lines[scLineNum] = scHeadLine lines.insert(scLineNum + 1, scMarker) lines.insert(scLineNum + 2, scTailLine) # update the line we're working with in case the we split it above if scLineNum == lineIndex: line = lines[lineIndex] # Next, we're going to replace the LOG_FUNCTION string from the # first line with our generated function's name and insert # the appropriate preprocessor directives to mark the boundaries # # Example: # "A(); LOG("Hello!);" # Becomes # "A(); # # 10 "injectedCode.fake" # { GENERATED_FUNC_NAME # # 10 "filename.cc" # ("Hello!"); # } # # 10 "filename.cc" # Close off the new scope lines.insert(scLineNum + 1, "}\r\n") offsetAfterLogFn = (charOffset + len(LOG_FUNCTION)) headOfLine = line[:charOffset] tailOfLine = line[offsetAfterLogFn:].rjust(len(line)) lines[lineIndex] = \ headOfLine \ + "\r\n# %d \"injectedCode.fake\"\r\n" % ppLineNum \ + "{ " + recordFn \ + "\r\n# %d \"%s\"\r\n" % (ppLineNum, ppFileName) \ + tailOfLine lastChar = c except ValueError as e: print "\r\n%s:%d: Error - %s\r\n\r\n%s\r\n" % ( ppFileName, ppLineNum, e.args[0], "".join(e.args[1])) sys.exit(1) # Last step, retrieve the generated code and insert it at the end recFns = functionGenerator.getRecordFunctionDefinitionsFor( firstFilename) codeToInject = "\r\n\r\n# 1 \"generatedCode.h\" 3\r\n" \ + "\r\n".join(recFns) if recFns: # Assert is okay here since this should have been caught the first time # we found NANO_LOG without a #include assert inlineCodeInjectionLineIndex lines.insert(inlineCodeInjectionLineIndex + 1, codeToInject) # Output all the lines for line in lines: output.write(line) output.close() functionGenerator.outputMappingFile(mapOutputFilename)
import numpy as np import matplotlib.pyplot as plt from scipy import signal from scipy.stats import norm import EncodingSchemes as ES import DecodingSchemes as DS import FunctionGenerator as FG if __name__ == '__main__': dt = 0.01 T_max = 4 time = np.arange(0, T_max, dt) S = list() S.append( FG.sum_of_sine_waves([2, -0.5, 0.75], [1.0, 3.0, 5.0], [0.0, 0.0, 0.0], 0.0, time)) S.append(FG.sum_of_sine_waves([-0.25], [1.0], [0.0], 0.05, time)) S.append( FG.sum_of_gaussian_wave([1, 0.5], [0.2, 0.75], [0.1, 0.1], 0.1, time)) # tbr_factors = [1.005, 1.005, 1.005] # sf_thresholds = [0.35, 0.05, 0.35] # mw_thresholds = [0.325, 0.015, 0.225] # mw_window = [3, 3, 3] # for i in range(len(S)): # spikes_TBR, threshold = ES.temporal_contrast(S[i], tbr_factors[i]) # signal_TBR = 2*DS.temporal_contrast(spikes_TBR, threshold)
def __init__(self, function_generator_resource_name): self.fg = FunctionGenerator.Agilent_33220x( function_generator_resource_name) self.__init_fg()