From b69ec3f6d953e67422dd32b72688cba850fd1b2e Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Mon, 13 Jan 2014 15:56:57 -0800 Subject: Initial commit --- bindings/haskell/.gitignore | 7 + bindings/haskell/README | 8 + bindings/haskell/Setup.hs | 22 ++ bindings/haskell/examples/simple.hs | 46 +++ bindings/haskell/ppamltracer.cabal | 62 ++++ bindings/haskell/src/PPAML/Tracer.hs | 268 ++++++++++++++ bindings/haskell/src/PPAML/Tracer/Exception.hs | 78 ++++ bindings/java/.gitignore | 7 + bindings/java/README | 12 + bindings/java/build.xml | 165 +++++++++ bindings/java/examples/build.xml | 41 +++ .../com/galois/ppaml/tracer/examples/Simple.java | 84 +++++ bindings/java/src/c/Makefile.am | 39 ++ .../java/src/c/com_galois_ppaml_tracer_Phase.c | 97 +++++ .../java/src/c/com_galois_ppaml_tracer_Tracer.c | 76 ++++ bindings/java/src/c/configure.ac | 58 +++ bindings/java/src/c/pointer.h | 38 ++ .../src/java/com/galois/ppaml/tracer/CWrapper.java | 184 ++++++++++ .../ppaml/tracer/ClockAcquisitionException.java | 35 ++ .../ppaml/tracer/NativeOutOfMemoryError.java | 38 ++ .../java/com/galois/ppaml/tracer/OTFException.java | 34 ++ .../galois/ppaml/tracer/OTFManagerException.java | 34 ++ .../tracer/OTFManagerInitializationException.java | 34 ++ .../ppaml/tracer/OTFWriterCloseException.java | 34 ++ .../ppaml/tracer/OTFWriterEntryException.java | 34 ++ .../galois/ppaml/tracer/OTFWriterException.java | 34 ++ .../ppaml/tracer/OTFWriterExitException.java | 34 ++ .../tracer/OTFWriterInitializationException.java | 34 ++ .../tracer/OTFWriterPhaseDefinitionException.java | 34 ++ .../OTFWriterProcessDefinitionException.java | 34 ++ .../ppaml/tracer/OTFWriterResolutionException.java | 34 ++ .../src/java/com/galois/ppaml/tracer/Phase.java | 220 ++++++++++++ .../com/galois/ppaml/tracer/TimingException.java | 34 ++ .../src/java/com/galois/ppaml/tracer/Tracer.java | 163 +++++++++ .../ppaml/tracer/UnexpectedReturnValueError.java | 37 ++ .../java/com/galois/ppaml/tracer/package-info.java | 80 +++++ bindings/python/.gitignore | 8 + bindings/python/MANIFEST.in | 21 ++ bindings/python/README | 11 + bindings/python/examples/simple.py | 49 +++ bindings/python/ppamltracer.py | 365 +++++++++++++++++++ bindings/python/setup.py | 34 ++ bindings/racket/.gitignore | 16 + bindings/racket/README | 11 + bindings/racket/main.rkt | 396 +++++++++++++++++++++ bindings/racket/manual.scrbl | 181 ++++++++++ 46 files changed, 3365 insertions(+) create mode 100644 bindings/haskell/.gitignore create mode 100644 bindings/haskell/README create mode 100644 bindings/haskell/Setup.hs create mode 100644 bindings/haskell/examples/simple.hs create mode 100644 bindings/haskell/ppamltracer.cabal create mode 100644 bindings/haskell/src/PPAML/Tracer.hs create mode 100644 bindings/haskell/src/PPAML/Tracer/Exception.hs create mode 100644 bindings/java/.gitignore create mode 100644 bindings/java/README create mode 100644 bindings/java/build.xml create mode 100644 bindings/java/examples/build.xml create mode 100644 bindings/java/examples/src/com/galois/ppaml/tracer/examples/Simple.java create mode 100644 bindings/java/src/c/Makefile.am create mode 100644 bindings/java/src/c/com_galois_ppaml_tracer_Phase.c create mode 100644 bindings/java/src/c/com_galois_ppaml_tracer_Tracer.c create mode 100644 bindings/java/src/c/configure.ac create mode 100644 bindings/java/src/c/pointer.h create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/CWrapper.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/ClockAcquisitionException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/NativeOutOfMemoryError.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFManagerException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFManagerInitializationException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterCloseException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterEntryException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterExitException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterInitializationException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterPhaseDefinitionException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterProcessDefinitionException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterResolutionException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/Phase.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/TimingException.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/Tracer.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/UnexpectedReturnValueError.java create mode 100644 bindings/java/src/java/com/galois/ppaml/tracer/package-info.java create mode 100644 bindings/python/.gitignore create mode 100644 bindings/python/MANIFEST.in create mode 100644 bindings/python/README create mode 100755 bindings/python/examples/simple.py create mode 100644 bindings/python/ppamltracer.py create mode 100755 bindings/python/setup.py create mode 100644 bindings/racket/.gitignore create mode 100644 bindings/racket/README create mode 100644 bindings/racket/main.rkt create mode 100644 bindings/racket/manual.scrbl (limited to 'bindings') diff --git a/bindings/haskell/.gitignore b/bindings/haskell/.gitignore new file mode 100644 index 0000000..805d057 --- /dev/null +++ b/bindings/haskell/.gitignore @@ -0,0 +1,7 @@ +# .gitignore for ppamltracer-haskell -*- conf -*- + +*.hi +*.o +dist*/ + +examples/simple diff --git a/bindings/haskell/README b/bindings/haskell/README new file mode 100644 index 0000000..3d9cf39 --- /dev/null +++ b/bindings/haskell/README @@ -0,0 +1,8 @@ + ppamltracer-haskell, v0.1.0 + +This package contains Haskell bindings to ppamltracer. They require GHC 7.6 or +later. + +This package uses the Cabal build system; normal Cabal build procedure applies. + +For examples of use, see the examples directory. diff --git a/bindings/haskell/Setup.hs b/bindings/haskell/Setup.hs new file mode 100644 index 0000000..fa38bd0 --- /dev/null +++ b/bindings/haskell/Setup.hs @@ -0,0 +1,22 @@ +{- Setup -- Cabal setup file for ppamltracer +Copyright (C) 2014 Galois, Inc. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . + +To contact Galois, complete the Web form at or +write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, Oregon, +97204-1622. -} + +import Distribution.Simple + +main = defaultMain diff --git a/bindings/haskell/examples/simple.hs b/bindings/haskell/examples/simple.hs new file mode 100644 index 0000000..478f25b --- /dev/null +++ b/bindings/haskell/examples/simple.hs @@ -0,0 +1,46 @@ +{- simple.hs -- basic ppamltracer example +This file is in the public domain. + +Compile this with + ghc --make simple.hs +-} + +{-# LANGUAGE LambdaCase #-} +module Main where + +import Control.Applicative ((<$>), (<*>)) +import Control.Monad (liftM) + +import PPAML.Tracer + +main :: IO () +main = do + -- Start ppamltracer. + withTracer "/tmp/simple_report" $ \tracer -> do + -- Register the factorial phase. + withPhase tracer "fact" $ \phase -> do + -- Print factorials. + putStr "Factorials:" + mapM_ (putStr . (' ':) . show) =<< mapM (fact phase) [0 .. 40] + putStrLn "" + -- Register the Fibonacci phase. + withPhase tracer "fib" $ \phase -> do + -- Print Fibonacci numbers. + putStr "Fibonacci numbers:" + mapM_ (putStr . (' ':) . show) =<< mapM (fib phase) [0 .. 25] + putStrLn "" + +{- Records that we're running inside the provided phase and computes a +factorial. -} +fact :: PhaseHandle -> Integer -> IO Integer +fact phase = withPhaseRunning phase . \case + 0 -> return 1 + n -> liftM (n*) $ fact phase (n - 1) + +{- Records that we're running inside the provided phase and computes a Fibonacci +number. -} +fib :: PhaseHandle -> Integer -> IO Integer +fib phase = withPhaseRunning phase . \case + 0 -> return 0 + 1 -> return 1 + n -> (+) <$> fib phase (n - 1) <*> fib phase (n - 2) diff --git a/bindings/haskell/ppamltracer.cabal b/bindings/haskell/ppamltracer.cabal new file mode 100644 index 0000000..5b6918e --- /dev/null +++ b/bindings/haskell/ppamltracer.cabal @@ -0,0 +1,62 @@ +-- ppamltracer.cabal -- Cabal build file for ppamltracer +-- Copyright (C) 2014 Galois, Inc. +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU General Public License as published by the Free Software +-- Foundation, either version 3 of the License, or (at your option) any later +-- version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +-- details. +-- +-- You should have received a copy of the GNU General Public License along with +-- this program. If not, see . +-- +-- To contact Galois, complete the Web form at +-- or write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, +-- Oregon, 97204-1622. + +cabal-version: >=1.10 +name: ppamltracer +version: 0.1.0 +synopsis: A lightweight tracing library +description: ppamltracer is a lightweight tracing library designed for explicit + instrumention of generated code. If you’re writing a compiler and need hard + data on your optimizer’s efficacy, ppamltracer is the library for you. This + package uses Haskell’s foreign function interface to wrap the C libppamltracer + API. + . + ppamltracer writes trace logs in the + , a free and open standard + developed by the Zentrum für Informationsdienste und Hochleistungsrechnen + (Center for Information Services and High-Performance Computing) at the + Technical University of Dresden. + . + We developed ppamltracer as part of DARPA’s + + (PPAML) project. +copyright: © 2014 Galois, Inc. +license: GPL-3 +author: Benjamin Barenblat +maintainer: bbarenblat@galois.com +category: Language +build-type: Simple +extra-source-files: examples/simple.hs +tested-with: GHC==7.6.3 + +library + hs-source-dirs: src + default-language: Haskell2010 + other-extensions: DeriveDataTypeable + , EmptyDataDecls + , ExistentialQuantification + , TemplateHaskell + build-depends: base + , deepseq >=1.2.0.0 && <2 + , hierarchical-exceptions <2 + extra-libraries: ppamltracer + exposed-modules: PPAML.Tracer + other-modules: PPAML.Tracer.Exception + ghc-options: -Wall -O2 diff --git a/bindings/haskell/src/PPAML/Tracer.hs b/bindings/haskell/src/PPAML/Tracer.hs new file mode 100644 index 0000000..ddff15c --- /dev/null +++ b/bindings/haskell/src/PPAML/Tracer.hs @@ -0,0 +1,268 @@ +{- PPAML.Tracer -- PPAML timing instrumentation system (Haskell bindings) +Copyright (C) 2014 Galois, Inc. + +This library is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This library is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this library. If not, see . + +To contact Galois, complete the Web form at or +write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, Oregon, +97204-1622. -} + +{-| Getting started with ppamltracer is easy. Because of Haskell’s intrinsic +laziness, though, getting meaningful results out of ppamltracer is slightly more +difficult. For instance, consider the following (correctly written) example: + +> import PPAML.Tracer +> +> main = +> withTracer "/tmp/my_report" $ \tracer -> +> withPhase tracer "phase 1" $ \phase -> +> withPhaseRunning phase doStuff +> withPhase tracer "phase 2" $ \phase -> do +> withPhaseRunning phase doOtherStuff +> withPhaseRunning phase doYetMoreStuff + +This creates a report which appears to record the total runtime of 'doStuff' +recorded as \"phase 1\" and the total runtime of 'doOtherStuff' and +'doYetMoreStuff' combined as \"phase 2\". In actuality, however, the report +does not record the total runtime – instead, + +> withPhaseRunning phase f + +records the time required to evaluate 'f'’s result to normal form. Thus, 'f' +can leverage infinite data as intermediate values; only 'f'’s final result need +be finite. -} + +{-# LANGUAGE EmptyDataDecls #-} +{-# LANGUAGE LambdaCase #-} +module PPAML.Tracer + ( -- * Tracers + Tracer, TracerHandle + , withTracer + -- * Phases + , Phase, PhaseHandle + , withPhase + -- * Timing + , withPhaseRunning, withPhaseRunning_ + -- * Exceptions + {-| ppamltracer defines a fairly detailed exception hierarchy; however, + all exceptions are truly exceptional cases, and they likely will not + occur in normal use. For reference, the hierarchy looks like this: + + @ +'Control.Exception.SomeException' +└─ 'TracerException' + ├─ 'OTFException' + │ ├─ 'OTFManagerException' + │ │ └─ 'OTFManagerInitializationFailure' + │ └─ 'OTFWriterException' + │ ├─ 'OTFWriterInitializationFailure' + │ ├─ 'OTFPhaseDefinitionFailure' + │ ├─ 'OTFPhaseEntryFailure' + │ ├─ 'OTFPhaseExitFailure' + │ ├─ 'OTFWriterCloseFailure' + │ ├─ 'OTFTraceResolutionFailure' + │ └─ 'OTFProcessDefinitionFailure' + └─ 'TimingException' + └─ 'ClockAcquisitionFailure' + @ -} + , TracerException + -- ** Open Trace Format exceptions + , OTFException + , OTFManagerException, OTFManagerInitializationFailure + , OTFWriterException, OTFWriterInitializationFailure, + OTFPhaseDefinitionFailure, OTFPhaseEntryFailure, OTFPhaseExitFailure, + OTFWriterCloseFailure, OTFTraceResolutionFailure, + OTFProcessDefinitionFailure + -- ** Timing exceptions + , TimingException, ClockAcquisitionFailure + ) where + +import Control.DeepSeq (NFData, ($!!)) +import Control.Exception (bracket_, throw) +import Foreign (Storable, Ptr, allocaBytes, peek) +import Foreign.C (CInt(CInt), CSize(CSize), CString, withCString) +import System.IO.Unsafe (unsafeDupablePerformIO) + +import PPAML.Tracer.Exception + + +-------------------------------- High-level API -------------------------------- + +{-| Constructs a 'Tracer' and executes the specified computation. The trace +report will be stored in Open Trace Format; all trace file paths will begin with +the specified path. + +Throws: + + * 'OTFManagerInitializationFailure' if the Open Trace Format manager could not + be initialized. + + * 'OTFWriterInitializationFailure' if the Open Trace Format writer could not + be initialized. + + * 'OTFTraceResolutionFailure' if setting the trace resolution failed. + + * 'OTFProcessDefinitionFailure' if defining the main OTF process failed. + + * 'OTFWriterCloseFailure' if the Open Trace Format writer could not be closed + after the computation ran. -} + +withTracer :: FilePath -> (TracerHandle -> IO a) -> IO a +withTracer reportBaseName f = + allocaBytes tracerSize $ \tracerHandle -> + bracket_ (tracerInit tracerHandle reportBaseName) + (tracerDone tracerHandle) + (f tracerHandle) + +{-| Constructs a 'Phase' and executes the specified computation. + +Throws 'OTFPhaseDefinitionFailure' if the phase could not be defined. -} +withPhase :: TracerHandle -- ^ the associated 'Tracer' + -> String -- ^ the name of the 'Phase' + -> (PhaseHandle -> IO a) + -> IO a +withPhase tracer name f = + allocaBytes phaseSize $ \phaseHandle -> + bracket_ (phaseInit tracer phaseHandle name) + (phaseDone phaseHandle) + (f phaseHandle) + +{-| Executes an IO action and evaluates its result to normal form, recording the +time required to do so in the provided 'Phase'. -} +withPhaseRunning :: NFData a => PhaseHandle -> IO a -> IO a +withPhaseRunning phase f = withPhaseRunning_ phase ((return $!!) =<< f) + +{-| Executes an IO action, recording the time required to do so in the provided +'Phase'. Unlinke 'withPhaseRunning', this function does /not/ evaluate the +action’s result. Use this function when you need finer-grained control over the +precise degree of evaluation than 'withPhaseRunning' offers. +-} +withPhaseRunning_ :: PhaseHandle -> IO a -> IO a +withPhaseRunning_ phase = bracket_ (phaseStart phase) (phaseStop phase) + + +----------------------------------- Tracers ------------------------------------ + +----- Data type ----- + +{-| Tracer state bundle. ppamltracer is fundamentally a set of stateful +operations; this data type dsecribes the state ppamltracer needs to operate +properly. A one-to-one mapping exists between 'Tracer's and trace reports, so +you will likely only need one 'Tracer' per program. -} +data Tracer + +foreign import ccall unsafe "ppaml/tracer/internal.h & ppaml_tracer_t_size" + ppaml_tracer_t_size :: Ptr CSize + +tracerSize :: Int +tracerSize = fromIntegral $ unsafeReadLibraryConstant ppaml_tracer_t_size + + +----- Initialization and finalization ----- + +type TracerHandle = Ptr Tracer + +foreign import ccall unsafe "ppaml/tracer.h ppaml_tracer_init" + ppaml_tracer_init :: TracerHandle -> CString -> IO CInt + +tracerInit :: TracerHandle -> FilePath -> IO () +tracerInit tracer reportNameBase = + withCString reportNameBase $ \cReportNameBase -> + ppaml_tracer_init tracer cReportNameBase >>= \case + 0 -> return () + 1 -> throw OTFManagerInitializationFailure + 2 -> throw OTFWriterInitializationFailure + 3 -> throw OTFTraceResolutionFailure + 4 -> throw OTFProcessDefinitionFailure + r -> unexpectedReturnCode r + +foreign import ccall unsafe "ppaml/tracer.h ppaml_tracer_done" + ppaml_tracer_done :: TracerHandle -> IO CInt + +tracerDone :: TracerHandle -> IO () +tracerDone tracer = + ppaml_tracer_done tracer >>= \case 0 -> return () + 1 -> throw OTFWriterCloseFailure + r -> unexpectedReturnCode r + + +------------------------------------ Phases ------------------------------------ + +----- Data type ----- + +-- | A phase of execution to trace and to gather timing statistics about. +data Phase + +foreign import ccall unsafe "ppaml/tracer/internal.h & ppaml_phase_t_size" + ppaml_phase_t_size :: Ptr CSize + +phaseSize :: Int +phaseSize = fromIntegral $ unsafeReadLibraryConstant ppaml_phase_t_size + + +----- Initialization and finalization ----- + +type PhaseHandle = Ptr Phase + +foreign import ccall unsafe "ppaml/tracer.h ppaml_phase_init" + ppaml_phase_init :: TracerHandle -> PhaseHandle -> CString -> IO CInt + +phaseInit :: TracerHandle -> PhaseHandle -> String -> IO () +phaseInit tracer phase name = + withCString name $ \cName -> + ppaml_phase_init tracer phase cName >>= \case + 0 -> return () + 1 -> throw OTFPhaseDefinitionFailure + r -> unexpectedReturnCode r + +foreign import ccall unsafe "ppaml/tracer.h ppaml_phase_done" + ppaml_phase_done :: PhaseHandle -> IO CInt + +phaseDone :: PhaseHandle -> IO () +phaseDone phase = + ppaml_phase_done phase >>= \case 0 -> return () + r -> unexpectedReturnCode r + + +----- Timing ----- + +foreign import ccall unsafe "ppaml/tracer.h ppaml_phase_start" + ppaml_phase_start :: PhaseHandle -> IO CInt + +phaseStart :: PhaseHandle -> IO () +phaseStart phase = + ppaml_phase_start phase >>= \case 0 -> return () + 1 -> throw ClockAcquisitionFailure + 2 -> throw OTFPhaseEntryFailure + r -> unexpectedReturnCode r + +foreign import ccall unsafe "ppaml/tracer.h ppaml_phase_stop" + ppaml_phase_stop :: PhaseHandle -> IO CInt + +phaseStop :: PhaseHandle -> IO () +phaseStop phase = + ppaml_phase_stop phase >>= \case 0 -> return () + 1 -> throw ClockAcquisitionFailure + 2 -> throw OTFPhaseExitFailure + r -> unexpectedReturnCode r + + +----------------------------------- Utility ------------------------------------ + +unsafeReadLibraryConstant :: Storable a => Ptr a -> a +unsafeReadLibraryConstant = unsafeDupablePerformIO . peek + +unexpectedReturnCode :: CInt -> a +unexpectedReturnCode code = + error $ "unexpected return code " ++ show code ++ "\n\ + \This is a bug in ppamltracer! Report it to the maintainers." diff --git a/bindings/haskell/src/PPAML/Tracer/Exception.hs b/bindings/haskell/src/PPAML/Tracer/Exception.hs new file mode 100644 index 0000000..ba77c84 --- /dev/null +++ b/bindings/haskell/src/PPAML/Tracer/Exception.hs @@ -0,0 +1,78 @@ +{- PPAML.Tracer.Exception -- exceptions used by ppamltracer +Copyright (C) 2014 Galois, Inc. + +This library is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This library is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this library. If not, see . + +To contact Galois, complete the Web form at or +write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, Oregon, +97204-1622. -} + +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE ExistentialQuantification #-} +{-# LANGUAGE TemplateHaskell #-} +module PPAML.Tracer.Exception where + +import Control.Exception (SomeException(SomeException)) +import Control.Exception.Hierarchical (mkAbstractException, mkException) + +-- | A generic ppamltracer error. Extends 'SomeException'. +mkAbstractException 'SomeException "TracerException" + + +-------------------------------- OTF exceptions -------------------------------- + +{-| An error related to Open Trace Format input and output. Extends +'TracerException'. -} +mkAbstractException 'TracerException "OTFException" + +-- | An error caused by the Open Trace Fromat manager. Extends 'OTFException'. +mkAbstractException 'OTFException "OTFManagerException" + +{-| Failure to initialize the Open Trace Format manager. Extends +'OTFManagerException'. -} +mkException 'OTFManagerException "OTFManagerInitializationFailure" + +-- | An error caused by the Open Trace Format writer. Extends 'OTFException'. +mkAbstractException 'OTFException "OTFWriterException" + +{-| Failure to initialize the Open Trace Format writer. Extends +'OTFWriterException'. -} +mkException 'OTFWriterException "OTFWriterInitializationFailure" + +-- | Failure to define a phase. Extends 'OTFWriterException'. +mkException 'OTFWriterException "OTFPhaseDefinitionFailure" + +-- | Failure to record entry into a phase. Extends 'OTFWriterException'. +mkException 'OTFWriterException "OTFPhaseEntryFailure" + +-- | Failure to record exit from a phase. Extends 'OTFWriterException'. +mkException 'OTFWriterException "OTFPhaseExitFailure" + +{-| Failure to close the Open Trace Format writer. Extends +'OTFWriterException'. -} +mkException 'OTFWriterException "OTFWriterCloseFailure" + +-- | Failure to set the tracer resolution. Extends 'OTFWriterException'. +mkException 'OTFWriterException "OTFTraceResolutionFailure" + +-- | Failure to define a process (i.e., a thread). Extends 'OTFWriterException'. +mkException 'OTFWriterException "OTFProcessDefinitionFailure" + + +------------------------------ Timing exceptions ------------------------------- + +-- | An error related to system timers. Extends 'TracerException'. +mkAbstractException 'TracerException "TimingException" + +-- | A failure to get the current clock time. Extends 'TimingException'. +mkException 'TimingException "ClockAcquisitionFailure" diff --git a/bindings/java/.gitignore b/bindings/java/.gitignore new file mode 100644 index 0000000..32690c1 --- /dev/null +++ b/bindings/java/.gitignore @@ -0,0 +1,7 @@ +# .gitignore for ppamltracer-java -*- conf -*- + +build/ +dist/ + +# Examples +examples/dist diff --git a/bindings/java/README b/bindings/java/README new file mode 100644 index 0000000..b5d4bfb --- /dev/null +++ b/bindings/java/README @@ -0,0 +1,12 @@ + ppamltracer-java, v0.1.0 + +This package contains Java bindings to ppamltracer. They require Java SE 5 or +later. + +This package uses the Java Native Interface. Therefore, building it produces +two artifacts: a jar, which you should install in your CLASSPATH, and a shared +library, which you should install in your LD_LIBRARY_PATH. If you have both +Ant and autotools installed, simply typing `ant' will build both artifacts and +install them in the `dist' directory. + +For examples of use, see the examples directory. diff --git a/bindings/java/build.xml b/bindings/java/build.xml new file mode 100644 index 0000000..d4e57f6 --- /dev/null +++ b/bindings/java/build.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/java/examples/build.xml b/bindings/java/examples/build.xml new file mode 100644 index 0000000..e7f6f4d --- /dev/null +++ b/bindings/java/examples/build.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/java/examples/src/com/galois/ppaml/tracer/examples/Simple.java b/bindings/java/examples/src/com/galois/ppaml/tracer/examples/Simple.java new file mode 100644 index 0000000..a698573 --- /dev/null +++ b/bindings/java/examples/src/com/galois/ppaml/tracer/examples/Simple.java @@ -0,0 +1,84 @@ +/* Simple -- basic ppamltracer example + * This file is in the public domain. */ + +package com.galois.ppaml.tracer.examples; + +import com.galois.ppaml.tracer.Phase; +import com.galois.ppaml.tracer.Tracer; + +public class Simple { + + protected Phase factPhase; + + protected Phase fibPhase; + + protected void go(Tracer tracer) { + // Register the phases. + factPhase = tracer.createPhase("fact"); + fibPhase = tracer.createPhase("fib"); + + // Print factorials. + System.out.print("Factorials:"); + for (int i = 0; i < 21; i++) { + System.out.print(" " + fact(i)); + } + System.out.println(); + + // Print Fibonacci numbers. + System.out.print("Fibonacci numbers:"); + for (int i = 0; i < 30; i++) { + System.out.print(" " + fib(i)); + } + System.out.println(); + + // Finalize phases and exit. + factPhase.close(); + fibPhase.close(); + } + + protected long fact(int n) { + // Record that we're running inside the factorial phase. + factPhase.start(); + // Compute the factorial. + long result; + if (n == 0) { + result = 1; + } else { + result = n * fact(n - 1); + } + // Return the result. + factPhase.stop(); + return result; + } + + protected int fib(int n) { + // Record that we're running inside the Fibonacci phase. + fibPhase.start(); + // Compute the nth Fibonacci number. + int result; + switch (n) { + case 0: + case 1: + result = n; + break; + default: + result = fib(n - 1) + fib(n - 2); + break; + } + // Return the result. + fibPhase.stop(); + return result; + } + + public static void main(String[] args) { + // Start ppamltracer. + Tracer tracer = new Tracer("/tmp/simple_report"); + + // Run the app. + (new Simple()).go(tracer); + + // Finalize ppamltracer and exit. + tracer.close(); + } + +} diff --git a/bindings/java/src/c/Makefile.am b/bindings/java/src/c/Makefile.am new file mode 100644 index 0000000..c30a4cf --- /dev/null +++ b/bindings/java/src/c/Makefile.am @@ -0,0 +1,39 @@ +# Makefile.am -- automake script for ppamltracer-java (JNI wrapper) +# Copyright (C) 2013, 2014 Galois, Inc. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +# To contact Galois, complete the Web form at +# or write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, +# Oregon, 97204-1622. + +ACLOCAL_AMFLAGS = -I m4 + +lib_LTLIBRARIES = libppamltracer_java.la +libppamltracer_java_la_SOURCES = \ + $(srcdir)/com_galois_ppaml_tracer_Phase.c \ + $(srcdir)/com_galois_ppaml_tracer_Phase.h \ + $(srcdir)/com_galois_ppaml_tracer_Tracer.c \ + $(srcdir)/com_galois_ppaml_tracer_Tracer.h \ + $(srcdir)/pointer.h +libppamltracer_java_la_CFLAGS = \ + -std=c99 \ + -Wall \ + -Wextra \ + -Wno-unused-parameter \ + -pedantic \ + -I@JAVA_HOME@/include +libppamltracer_java_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -export-symbols-regex '^Java_' diff --git a/bindings/java/src/c/com_galois_ppaml_tracer_Phase.c b/bindings/java/src/c/com_galois_ppaml_tracer_Phase.c new file mode 100644 index 0000000..76f346b --- /dev/null +++ b/bindings/java/src/c/com_galois_ppaml_tracer_Phase.c @@ -0,0 +1,97 @@ +/* com_galois_ppaml_tracer_Phase.c -- JNI wrapper for com.galois.ppaml.tracer.Phase + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +#include + +#include + +#include +#include + +#include "pointer.h" + +JNIEXPORT +jlong JNICALL Java_com_galois_ppaml_tracer_Phase_mallocPhase( + JNIEnv *const env, + jclass Phase) +{ + return jlong_of_pointer(malloc(sizeof(ppaml_phase_t))); +} + +JNIEXPORT +jint JNICALL Java_com_galois_ppaml_tracer_Phase_ppaml_1phase_1init( + JNIEnv *const env, + jclass Phase, + jlong tracer, + jlong phase, + jstring name) +{ + jint r; + // Allocate memory. + const char *const cName = (*env)->GetStringUTFChars(env, name, NULL); + if (cName == NULL) { + r = -1; + goto done; + } + // Perform the operation. + r = ppaml_phase_init( + pointer_of_jlong(tracer), + pointer_of_jlong(phase), + cName); + // Clean up. +done: (*env)->ReleaseStringUTFChars(env, name, cName); + return r; +} + +JNIEXPORT +jint JNICALL Java_com_galois_ppaml_tracer_Phase_ppaml_1phase_1done( + JNIEnv *const env, + jclass Phase, + jlong phase) +{ + return ppaml_phase_done(pointer_of_jlong(phase)); +} + +JNIEXPORT +void JNICALL Java_com_galois_ppaml_tracer_Phase_freePhase( + JNIEnv *const env, + jclass Phase, + jlong phase) +{ + free(pointer_of_jlong(phase)); +} + +JNIEXPORT +jint JNICALL Java_com_galois_ppaml_tracer_Phase_ppaml_1phase_1start( + JNIEnv *const env, + jclass Phase, + jlong phase) +{ + return ppaml_phase_start(pointer_of_jlong(phase)); +} + +JNIEXPORT +jint JNICALL Java_com_galois_ppaml_tracer_Phase_ppaml_1phase_1stop( + JNIEnv *const env, + jclass Phase, + jlong phase) +{ + return ppaml_phase_stop(pointer_of_jlong(phase)); +} diff --git a/bindings/java/src/c/com_galois_ppaml_tracer_Tracer.c b/bindings/java/src/c/com_galois_ppaml_tracer_Tracer.c new file mode 100644 index 0000000..2c23966 --- /dev/null +++ b/bindings/java/src/c/com_galois_ppaml_tracer_Tracer.c @@ -0,0 +1,76 @@ +/* com_galois_ppaml_tracer_Tracer.c -- JNI wrapper for com.galois.ppaml.tracer.Tracer + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +#include + +#include + +#include +#include + +#include "pointer.h" + +JNIEXPORT +jlong JNICALL Java_com_galois_ppaml_tracer_Tracer_mallocTracer( + JNIEnv *const env, + jclass Tracer) +{ + return jlong_of_pointer(malloc(sizeof(ppaml_tracer_t))); +} + +JNIEXPORT +jint JNICALL Java_com_galois_ppaml_tracer_Tracer_ppaml_1tracer_1init( + JNIEnv *const env, + jclass Tracer, + jlong tracer, + jstring reportNameBase) +{ + jint r; + // Allocate memory. + const char *const cReportNameBase = + (*env)->GetStringUTFChars(env, reportNameBase, NULL); + if (cReportNameBase == NULL) { + r = -1; + goto done; + } + // Perform the operation. + r = ppaml_tracer_init(pointer_of_jlong(tracer), cReportNameBase); + // Clean up. +done: (*env)->ReleaseStringUTFChars(env, reportNameBase, cReportNameBase); + return r; +} + +JNIEXPORT +jint JNICALL Java_com_galois_ppaml_tracer_Tracer_ppaml_1tracer_1done( + JNIEnv *const env, + jclass Tracer, + jlong tracer) +{ + return ppaml_tracer_done(pointer_of_jlong(tracer)); +} + +JNIEXPORT +void JNICALL Java_com_galois_ppaml_tracer_Tracer_freeTracer( + JNIEnv *const env, + jclass Tracer, + jlong tracer) +{ + free(pointer_of_jlong(tracer)); +} diff --git a/bindings/java/src/c/configure.ac b/bindings/java/src/c/configure.ac new file mode 100644 index 0000000..0d1556b --- /dev/null +++ b/bindings/java/src/c/configure.ac @@ -0,0 +1,58 @@ +# configure.ac -- autoconf script for ppamltracer-java (JNI wrapper) +# Copyright (C) 2013, 2014 Galois, Inc. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +# To contact Galois, complete the Web form at +# or write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, +# Oregon, 97204-1622. + +# Fire up Autoconf. +AC_PREREQ([2.69]) +AC_INIT([ppamltracer-java], [0.1.0], [bbarenblat@galois.com]) + +# Fire up Automake. +AM_INIT_AUTOMAKE([-Wall -Wno-gnu -Werror foreign no-dist-gzip dist-bzip2]) +AC_CONFIG_MACRO_DIR([m4]) + +# Build quietly. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +# Build a C library. +AC_PROG_CC +AC_PROG_CC_C99 +# Automake 1.12 seems to require this, but automake 1.11 doesn't recognize it. +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +LT_INIT + +# JNI +AC_ARG_VAR([JAVA_HOME], [path to JDK installation]) +if test -z "$JAVA_HOME"; then + AC_MSG_ERROR([empty JAVA_HOME environment variable; please set it to the path to your JDK installation]) +fi +AC_SUBST([JAVA_HOME]) + +# ppamltracer +AC_CHECK_HEADER([ppaml/tracer.h], + [], + [AC_MSG_ERROR([ppamltracer development headers are required (are they in C_INCLUDE_PATH?)])]) +AC_CHECK_LIB([ppamltracer], [ppaml_tracer_init], + [], + [AC_MSG_ERROR([libppamltracer is required (is it in LIBRARY_PATH?)])]) + +# Generate Makefile. +AC_CONFIG_FILES([Makefile]) + +# All done. +AC_OUTPUT diff --git a/bindings/java/src/c/pointer.h b/bindings/java/src/c/pointer.h new file mode 100644 index 0000000..123025d --- /dev/null +++ b/bindings/java/src/c/pointer.h @@ -0,0 +1,38 @@ +/* pointer.h -- pointer <-> jlong casts + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +#ifndef PPAML_TRACER_JAVA_POINTER_H +#define PPAML_TRACER_JAVA_POINTER_H + +#include + +#include + +inline void *pointer_of_jlong(const jlong value) +{ + return (void *)(intptr_t)value; +} + +inline jlong jlong_of_pointer(void *const pointer) +{ + return (jlong)(intptr_t)pointer; +} + +#endif diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/CWrapper.java b/bindings/java/src/java/com/galois/ppaml/tracer/CWrapper.java new file mode 100644 index 0000000..5a7887a --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/CWrapper.java @@ -0,0 +1,184 @@ +/* CWrapper -- wrapping C structures + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * A class which wraps a C structure and associated functions. + * + *

This class is intended to work hand-in-hand with Java Native Interface + * code that follows a four-stage lifecycle: + * + *

+ *
Allocation
The system reserves memory and resources needed by + * the structure.
+ *
Initialization
The system installs data into the structure to + * make it ready for use.
+ *
Finalization
The system cleans up the data structure under the + * assumption that it will not be used anymore.
+ *
Freeing
The system releases memory and resources needed by the + * structure.
+ *
+ * + * This class defines abstract methods associated with each of these phases; by + * defining contracts on them, it can then consolidate the phases into two + * concretely-implemented operations: + * + *
+ *
Open
The system allocates and initializes the underlying + * structure.
+ *
Close
The system finalizes and frees the underlying + * structure.
+ *
+ * + *

This class is not intended to be instantiated directly. Only + * instantiate its concrete subclasses. + */ +abstract class CWrapper { + + /** + * C pointer to the underlying data structure. + */ + protected long cPointer; + + + /////////////////////////// Low-level life cycle /////////////////////////// + + /** + * Reserves memory and resources needed by the structure. + * + *

Precondition: cPointer is 0. + * + *

Postcondition: If allocation was successful, + * cPointer is not 0. + */ + abstract protected void allocateCPointer(); + + /** + * Installs data into the structure to make it ready for use. + * + *

Precondition: Allocation succeeded. + */ + abstract protected void initializeCPointer(); + + /** + * Cleans up the structure under the assumption that it will not be used + * anymore. + * + *

Precondition: Initialization succeeded. + */ + abstract protected void finalizeCPointer(); + + /** + * Releases memory and resources needed by the structure. + * + *

Precondition: cPointer is not 0.
+ * Precondition: Finalization succeeded. + * + *

Postcondition: cPointer is 0. + */ + abstract protected void freeCPointer(); + + + ////////////////////////// High-level life cycle ////////////////////////// + + /** + * Allocates and initializes the underlying structure. + * + * @throws OpenedException the underlying structure has already been opened. + * + * @throws NativeOutOfMemoryError allocation failed. + */ + protected synchronized void open() { + if (cPointer != 0) { + throw new OpenedException(); + } + allocateCPointer(); + if (cPointer == 0) { + throw new NativeOutOfMemoryError(); + } + initializeCPointer(); + } + + /** + * Finalizes and frees the underlying structure. + * + * @throws ClosedException the underlying structure has already been closed. + */ + public synchronized void close() { + if (cPointer == 0) { + throw new ClosedException(); + } + finalizeCPointer(); + freeCPointer(); + cPointer = 0; + } + + + ////////////////////////// Associated exceptions ////////////////////////// + + /** + * Signals that the underlying structure is already open. + */ + public class OpenedException extends java.lang.IllegalStateException { + + static final long serialVersionUID = -7226578680647930527L; + + /** + * Constructs a CWrapper.OpenedException with no detail + * message. + */ + protected OpenedException() { + super(); + } + + } + + /** + * Signals that the underlying structure is already closed. + */ + public class ClosedException extends java.lang.IllegalStateException { + + static final long serialVersionUID = -2471059099211958977L; + + /** + * Constructs a CWrapper.ClosedException with no detail + * message. + */ + protected ClosedException() { + super(); + } + + } + + + ////////////////////////////// Miscellaneous ////////////////////////////// + + @Override + protected void finalize() { + close(); + } + + @Override + protected Object clone() throws java.lang.CloneNotSupportedException { + throw new java.lang.CloneNotSupportedException(); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/ClockAcquisitionException.java b/bindings/java/src/java/com/galois/ppaml/tracer/ClockAcquisitionException.java new file mode 100644 index 0000000..68b212d --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/ClockAcquisitionException.java @@ -0,0 +1,35 @@ +/* ClockAcquisitionException -- failure to get the time + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to get the current time. This could be due to any number + * of operating-system dependent factors. + */ +public class ClockAcquisitionException extends TimingException { + + static final long serialVersionUID = -5730008048750495655L; + + protected ClockAcquisitionException() { + super("could not get current time"); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/NativeOutOfMemoryError.java b/bindings/java/src/java/com/galois/ppaml/tracer/NativeOutOfMemoryError.java new file mode 100644 index 0000000..7c5ca3e --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/NativeOutOfMemoryError.java @@ -0,0 +1,38 @@ +/* NativeOutOfMemoryError -- failure to allocate with malloc + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to allocate on the native heap. + */ +public class NativeOutOfMemoryError extends java.lang.Error { + + static final long serialVersionUID = 1826582972785125106L; + + protected NativeOutOfMemoryError() { + super(); + } + + protected NativeOutOfMemoryError(String s) { + super(s); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFException.java new file mode 100644 index 0000000..a639c69 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFException.java @@ -0,0 +1,34 @@ +/* OTFException -- signals an OTF-related failure + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure related to the Open Trace Format API. + */ +public class OTFException extends java.lang.RuntimeException { + + static final long serialVersionUID = 29573934735841980L; + + protected OTFException(String s) { + super(s); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFManagerException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFManagerException.java new file mode 100644 index 0000000..b41d528 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFManagerException.java @@ -0,0 +1,34 @@ +/* OTFManagerException -- signals a failure related to the OTF manager + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure related to the Open Trace Format file manager. + */ +public class OTFManagerException extends OTFException { + + static final long serialVersionUID = 9158227932426782179L; + + protected OTFManagerException(String s) { + super(s); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFManagerInitializationException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFManagerInitializationException.java new file mode 100644 index 0000000..e4f61a0 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFManagerInitializationException.java @@ -0,0 +1,34 @@ +/* OTFManagerInitializationException -- failure to start the OTF manager + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to initialize the Open Trace Format file manager. + */ +public class OTFManagerInitializationException extends OTFManagerException { + + static final long serialVersionUID = 8357422459731580151L; + + protected OTFManagerInitializationException() { + super("could not initialize Open Trace Format file manager"); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterCloseException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterCloseException.java new file mode 100644 index 0000000..6b08d7d --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterCloseException.java @@ -0,0 +1,34 @@ +/* OTFWriterCloseException -- failure to close the OTF writer + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to close the Open Trace Format writer. + */ +public class OTFWriterCloseException extends OTFWriterException { + + static final long serialVersionUID = -3744439236064694516L; + + protected OTFWriterCloseException() { + super("could not close Open Trace Format writer"); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterEntryException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterEntryException.java new file mode 100644 index 0000000..e330941 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterEntryException.java @@ -0,0 +1,34 @@ +/* OTFWriterEntryException -- failure to record phase entry + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to record {@link Phase} entry. + */ +public class OTFWriterEntryException extends OTFWriterException { + + static final long serialVersionUID = -3863070199086068755L; + + protected OTFWriterEntryException() { + super("could not record phase start"); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterException.java new file mode 100644 index 0000000..f1d0e3c --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterException.java @@ -0,0 +1,34 @@ +/* OTFWriterException -- failure related to the OTF writer + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure related to the Open Trace Format writer. + */ +public class OTFWriterException extends OTFException { + + static final long serialVersionUID = -8501407892120456005L; + + protected OTFWriterException(String s) { + super(s); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterExitException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterExitException.java new file mode 100644 index 0000000..502e4bf --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterExitException.java @@ -0,0 +1,34 @@ +/* OTFWriterExitException -- failure to record phase exit + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to record {@link Phase} entry. + */ +public class OTFWriterExitException extends OTFWriterException { + + static final long serialVersionUID = 2672929667606300155L; + + protected OTFWriterExitException() { + super("could not record phase end"); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterInitializationException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterInitializationException.java new file mode 100644 index 0000000..315ceb2 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterInitializationException.java @@ -0,0 +1,34 @@ +/* OTFWriterInitializationException -- failure to start the OTF writer + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to initialize the Open Trace Format writer. + */ +public class OTFWriterInitializationException extends OTFWriterException { + + static final long serialVersionUID = -160590670499907090L; + + protected OTFWriterInitializationException() { + super("could not open Open Trace Format writer"); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterPhaseDefinitionException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterPhaseDefinitionException.java new file mode 100644 index 0000000..225b32b --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterPhaseDefinitionException.java @@ -0,0 +1,34 @@ +/* OTFWriterPhaseDefinitionException -- failure to define an OTF phase + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to define a {@link Phase}. + */ +public class OTFWriterPhaseDefinitionException extends OTFWriterException { + + static final long serialVersionUID = -5221693771344940262L; + + protected OTFWriterPhaseDefinitionException() { + super("could not define phase"); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterProcessDefinitionException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterProcessDefinitionException.java new file mode 100644 index 0000000..dc95859 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterProcessDefinitionException.java @@ -0,0 +1,34 @@ +/* OTFWriterProcessDefinitionException -- failure to define an OTF process + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to define an Open Trace Format process (thread). + */ +public class OTFWriterProcessDefinitionException extends OTFWriterException { + + static final long serialVersionUID = -2403392867513685061L; + + protected OTFWriterProcessDefinitionException(String processName) { + super("could not define Open Trace Format Process " + processName); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterResolutionException.java b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterResolutionException.java new file mode 100644 index 0000000..bccacc1 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/OTFWriterResolutionException.java @@ -0,0 +1,34 @@ +/* OTFWriterResolutionException -- failure to set the trace resolution + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure to set the time resolution of a {@link Tracer}. + */ +public class OTFWriterResolutionException extends OTFWriterException { + + static final long serialVersionUID = 7655059683403795873L; + + protected OTFWriterResolutionException() { + super("could not set trace resolution"); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/Phase.java b/bindings/java/src/java/com/galois/ppaml/tracer/Phase.java new file mode 100644 index 0000000..23ed2f4 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/Phase.java @@ -0,0 +1,220 @@ +/* Phase -- wrapped ppaml_phase_t + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * A phase of execution to trace. This class exports no public constructors; + * to instantiate it, use Tracer.createPhase. + */ +public final class Phase extends CWrapper { + + /** + * The Tracer this phase is associated with. + */ + private final Tracer tracer; + + /** + * The name of the phase. + */ + private final String name; + + /** + * Creates and initializes a Phase. You should not call this; + * call {@link Tracer.createPhase} instead. + * + * @param tracer the {@link Tracer} to associate the Phase + * with. + * + * @param name the name of the phase. + */ + protected Phase(Tracer tracer, final String name) { + this.tracer = tracer; + this.name = name; + super.open(); + } + + + ////////////////////////// Low-level life cycle ////////////////////////// + + ///// JNI shared library ///// + + static { + System.loadLibrary("ppamltracer_java"); + } + + /** + * Wraps malloc to allocate a ppaml_phase_t. + * + * @return Same as malloc. + */ + private static native long mallocPhase(); + + /** + * Wraps ppaml_phase_init. + * + * @return -1 if converting name from a String to + * a char * failed; all other return codes are the same as + * ppaml_phase_init. + */ + private static native int ppaml_phase_init( + long tracer, + long phase, + final String reportNameBase); + + /** + * Wraps ppaml_phase_done. + * + * @return Same as ppaml_phase_done. + */ + private static native int ppaml_phase_done(long phase); + + /** + * Wraps free. + */ + private static native void freePhase(long phase); + + + ///// JNI adapter code ///// + + @Override + protected void allocateCPointer() { + this.cPointer = mallocPhase(); + } + + /** + * Installs data into the structure to make it ready for use. + * + *

Precondition: Initialization succeeded. + * + * @throws OutOfMemoryError converting name from a + * String to a char * failed. + * + * @throws OTFWriterPhaseDefinitionException defining the OTF phase failed. + */ + @Override + protected void initializeCPointer() { + assert this.cPointer != 0; + assert tracer != null; + assert name != null; + final int r = ppaml_phase_init(tracer.cPointer, this.cPointer, name); + switch (r) { + case 0: + break; + case -1: + throw new java.lang.OutOfMemoryError( + "failed to convert Java string to C string"); + case 1: + throw new OTFWriterPhaseDefinitionException(); + default: + throw new UnexpectedReturnValueError(r); + } + } + + @Override + protected void finalizeCPointer() { + assert this.cPointer != 0; + final int r = ppaml_phase_done(this.cPointer); + if (r != 0) { + throw new UnexpectedReturnValueError(r); + } + } + + @Override + protected void freeCPointer() { + assert this.cPointer != 0; + freePhase(this.cPointer); + } + + + ////////////////////////// Starting and stopping ////////////////////////// + + ///// JNI shared library ///// + + /** + * Wraps ppaml_phase_start. + * + * @return Same as ppaml_phase_start. + */ + private static native int ppaml_phase_start(long phase); + + /** + * Wraps ppaml_phase_stop. + * + * @return Same as ppaml_phase_stop. + */ + private static native int ppaml_phase_stop(long phase); + + + ///// JNI adapter code ///// + + /** + * Records the start of a Phase. + * + * @throws ClosedException the Phase has been closed. + * + * @throws ClockAcquisitionException getting the time failed. + * + * @throws OTFWriterEntryException recording the phase start failed. + */ + public void start() { + if (this.cPointer == 0) { + throw new ClosedException(); + } + final int r = ppaml_phase_start(this.cPointer); + switch (r) { + case 0: + break; + case 1: + throw new ClockAcquisitionException(); + case 2: + throw new OTFWriterEntryException(); + default: + throw new UnexpectedReturnValueError(r); + } + } + + /** + * Records the end of a Phase. + * + * @throws ClosedException the Phase has been closed. + * + * @throws ClockAcquisitionException getting the time failed. + * + * @throws OTFWriterExitException recording the phase stop failed. + */ + public void stop() { + if (this.cPointer == 0) { + throw new ClosedException(); + } + final int r = ppaml_phase_stop(this.cPointer); + switch (r) { + case 0: + break; + case 1: + throw new ClockAcquisitionException(); + case 2: + throw new OTFWriterExitException(); + default: + throw new UnexpectedReturnValueError(r); + } + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/TimingException.java b/bindings/java/src/java/com/galois/ppaml/tracer/TimingException.java new file mode 100644 index 0000000..da1afad --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/TimingException.java @@ -0,0 +1,34 @@ +/* TimingException -- signals a timing failure + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals a failure related to timing. + */ +public class TimingException extends java.lang.RuntimeException { + + static final long serialVersionUID = -1441057354704045107L; + + protected TimingException(String s) { + super(s); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/Tracer.java b/bindings/java/src/java/com/galois/ppaml/tracer/Tracer.java new file mode 100644 index 0000000..fe0a180 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/Tracer.java @@ -0,0 +1,163 @@ +/* Tracer -- wrapped ppaml_tracer_t + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * State class for ppamltracer. + * + *

ppamltracer is fundamentally a set of stateful operations; a + * Tracer object holds the state ppamltracer needs to operate + * properly. + */ +public final class Tracer extends CWrapper { + + /** + * Base file path for trace report output. + */ + private final String reportNameBase; + + /** + * Creates and initializes a Tracer. The trace report will be + * stored in Open Trace Format. + * + * @param reportNameBase all trace file paths will begin with this path. + */ + public Tracer(final String reportNameBase) { + this.reportNameBase = reportNameBase; + super.open(); + } + + /** + * Creates and initializes a {@link Phase} associated with this + * Tracer. + * + * @param name the name of the phase. + */ + public Phase createPhase(final String name) { + return new Phase(this, name); + } + + + ////////////////////////// Low-level life cycle ////////////////////////// + + ///// JNI shared library ///// + + static { + System.loadLibrary("ppamltracer_java"); + } + + /** + * Wraps malloc to allocate a ppaml_tracer_t. + * + * @return Same as malloc. + */ + private static native long mallocTracer(); + + /** + * Wraps ppaml_tracer_init. + * + * @return -1 if converting reportNameBase from a + * String to a char * failed; all other return + * codes are the same as ppaml_tracer_init. + */ + private static native int ppaml_tracer_init( + long tracer, + final String reportNameBase); + + /** + * Wraps ppaml_tracer_done. + * + * @return Same as ppaml_tracer_done. + */ + private static native int ppaml_tracer_done(long tracer); + + /** + * Wraps free. + */ + private static native void freeTracer(long tracer); + + + ///// JNI adapter code ///// + + @Override + protected void allocateCPointer() { + this.cPointer = mallocTracer(); + } + + /** + * Installs data into the structure to make it ready for use. + * + *

Precondition: Initialization succeeded. + * + * @throws OutOfMemoryError converting reportNameBase from a + * String to a char * failed. + * + * @throws OTFManagerInitializationException the Open Trace Format file + * manager could not be initialized. + * + * @throws OTFWriterInitializationException the Open Trace Format writer + * could not be initialized. + * + * @throws OTFWriterResolutionException setting the trace resolution failed. + * + * @throws OTFWriterProcessDefinitionException defining the main OTF process + * failed. + */ + @Override + protected void initializeCPointer() { + assert this.cPointer != 0; + assert reportNameBase != null; + final int r = ppaml_tracer_init(this.cPointer, reportNameBase); + switch (r) { + case 0: + break; + case -1: + throw new java.lang.OutOfMemoryError( + "failed to convert Java string to C string"); + case 1: + throw new OTFManagerInitializationException(); + case 2: + throw new OTFWriterInitializationException(); + case 3: + throw new OTFWriterResolutionException(); + case 4: + throw new OTFWriterProcessDefinitionException("main"); + default: + throw new UnexpectedReturnValueError(r); + } + } + + @Override + protected void finalizeCPointer() { + assert this.cPointer != 0; + final int r = ppaml_tracer_done(this.cPointer); + if (r != 0) { + throw new UnexpectedReturnValueError(r); + } + } + + @Override + protected void freeCPointer() { + assert this.cPointer != 0; + freeTracer(this.cPointer); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/UnexpectedReturnValueError.java b/bindings/java/src/java/com/galois/ppaml/tracer/UnexpectedReturnValueError.java new file mode 100644 index 0000000..e536073 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/UnexpectedReturnValueError.java @@ -0,0 +1,37 @@ +/* UnexpectedReturnValueError -- unexpected return value from C API + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +package com.galois.ppaml.tracer; + +/** + * Signals an unexpected return value from libppamltracer. If this error is + * thrown, it indicates a bug in ppamltracer, and you should report it to the + * developers. + */ +public class UnexpectedReturnValueError extends java.lang.Error { + + static final long serialVersionUID = -2476858873119724922L; + + protected UnexpectedReturnValueError(int r) { + super("unexpected return value " + r + "\n" + + "This is a bug in ppamltracer! Report it to the maintainers."); + } + +} diff --git a/bindings/java/src/java/com/galois/ppaml/tracer/package-info.java b/bindings/java/src/java/com/galois/ppaml/tracer/package-info.java new file mode 100644 index 0000000..f922274 --- /dev/null +++ b/bindings/java/src/java/com/galois/ppaml/tracer/package-info.java @@ -0,0 +1,80 @@ +/* package-info.java -- package information + * Copyright (C) 2014 Galois, Inc. + * + * This library is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this library. If not, see . + * + * To contact Galois, complete the Web form at + * or write to Galois, Inc., 421 Southwest + * 6th Avenue, Suite 300, Portland, Oregon, 97204-1622. */ + +/** + * A lightweight, portable tracing library for instrumenting generated code. + * + *

ppamltracer is a lightweight, portable tracing library designed for + * explicit instrumention of generated code. If you're writing a compiler and + * need hard data on your optimizer's efficacy, ppamltracer is the library for + * you. This Java package provides bindings to the libppamltracer C API. + * + *

This package's usage can be summed up in a few lines: + * + *

+ *   // Create report.
+ *   Tracer tracer = new Tracer("/tmp/my_report");
+ *
+ *   // Register phase 1 and do stuff.
+ *   Phase phase = tracer.createPhase("phase 1");
+ *   phase.start();
+ *   doStuff();
+ *   phase.stop();
+ *   phase.close();
+ *
+ *   // Register phase 2 and do different stuff.
+ *   phase = tracer.createPhase("phase 2");
+ *   // Other stuff
+ *   phase.start();
+ *   doOtherStuff();
+ *   phase.stop();
+ *   // Yet more stuff
+ *   phase.start();
+ *   doYetMoreStuff();
+ *   phase.stop();
+ *
+ *   // Clean up.
+ *   phase.close();
+ *   tracer.close();
+ * 
+ * + *

This creates a report with the total runtime of doStuff + * recorded as "phase 1" and the total runtime of doOtherStuff and + * doYetMoreStuff combined as "phase 2". + * + *

com.galois.ppaml.tracer.examples.Simple, included in the + * distribution, contains a more lengthy example. + * + *

ppamltracer writes trace logs in the + * Open Trace Format, a free and + * open standard developed by the Zentrum für Informationsdienste und + * Hochleistungsrechnen (Center for Information Services and High-Performance + * Computing) at the Technical University of Dresden. + * + *

We developed ppamltracer as part of DARPA's + * Probabilistic + * Programming for Advancing Machine Learning (PPAML) project. + * + * @author Galois, Inc. + * + * @version 0.1.0 + */ + +package com.galois.ppaml.tracer; diff --git a/bindings/python/.gitignore b/bindings/python/.gitignore new file mode 100644 index 0000000..4ac65cb --- /dev/null +++ b/bindings/python/.gitignore @@ -0,0 +1,8 @@ +# .gitignore for ppamltracer-python -*- conf -*- + +# Python +*.pyc + +# distutils +MANIFEST +dist/ diff --git a/bindings/python/MANIFEST.in b/bindings/python/MANIFEST.in new file mode 100644 index 0000000..6ec6c9b --- /dev/null +++ b/bindings/python/MANIFEST.in @@ -0,0 +1,21 @@ +# MANIFEST.in -- manifest template for source distributions +# Copyright (C) 2013 Galois, Inc. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +# To contact Galois, complete the Web form at +# or write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, +# Oregon, 97204-1622. + +recursive-include examples *.py diff --git a/bindings/python/README b/bindings/python/README new file mode 100644 index 0000000..35a6bbd --- /dev/null +++ b/bindings/python/README @@ -0,0 +1,11 @@ + ppamltracer-python, v0.1.0 + +This package provides Python bindings to ppamltracer. They require Python 2.7. + +This package uses distutils for installation; you can run + + python setup.py install + +to install the package. + +For examples of use, see the examples directory. diff --git a/bindings/python/examples/simple.py b/bindings/python/examples/simple.py new file mode 100755 index 0000000..350c85a --- /dev/null +++ b/bindings/python/examples/simple.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# simple.py -- basic ppamltracer-python example +# This file is in the public domain. + +import os +import sys + +from ppamltracer import Tracer + +def main(): + # Disable buffering on stdout so we can see the numbers as they are printed. + sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) + # Start ppamltracer. + with Tracer("/tmp/simple_report") as tracer: + # Register the factorial phase. + with tracer.create_phase("fact") as phase: + # Print factorials. + print "Factorials:", + for i in range(21): + print fact(phase, i), + print + # Register the Fibonacci phase. + with tracer.create_phase("fib") as phase: + # Print Fibonacci numbers. + print "Fibonacci numbers: ", + for i in range(24): + print fib(phase, i), + print + +def fact(phase, n): + # Record that we're running inside the factorial phase. + with phase.running(): + # Compute the factorial. + if n == 0: + return 1 + else: + return n * fact(phase, n - 1) + +def fib(phase, n): + # Record that we're running inside the Fibonacci phase. + with phase.running(): + # Compute the nth Fibonacci number. + if n == 0 or n == 1: + return n + else: + return fib(phase, n - 1) + fib(phase, n - 2) + +if __name__ == '__main__': + main() diff --git a/bindings/python/ppamltracer.py b/bindings/python/ppamltracer.py new file mode 100644 index 0000000..dde85a3 --- /dev/null +++ b/bindings/python/ppamltracer.py @@ -0,0 +1,365 @@ +# ppamltracer -- Python bindings to ppamltracer +# Copyright (C) 2013 Galois, Inc. +# +# This library is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this library. If not, see . +# +# To contact Galois, complete the Web form at +# or write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, +# Oregon, 97204-1622. + +"""A tracing library for explicit instrumentation of generated code. + +ppamltracer is a lightweight, portable tracing library designed for +explicit instrumention of generated code. If you're writing a compiler +and need hard data on your optimizer's efficacy, ppamltracer is the +library for you. ppamltracer-python provides a high-level Python API on +top of the libppamltracer C API. + +ppamltracer-python's usage can be summed up in a couple lines: + + from ppamltracer import Tracer + with Tracer("/tmp/my_report") as tracer: + with tracer.create_phase("phase 1") as phase: + with phase.running(): + do_stuff() + with tracer.create_phase("phase 2") as phase: + with phase.running(): + do_other_stuff() + with phase.running(): + do_yet_more_stuff() + +This creates a report with the total runtime of do_stuff recorded as +"phase 1", and the total runtime of do_other_stuff and do_yet_more_stuff +combined as "phase 2". + +The ppamltracer-python distribution also contains a more lengthy example +in the "examples" directory. + +ppamltracer writes trace logs in the Open Trace Format [1], a free and +open standard developed by the Zentrum fuer Informationsdienste und +Hochleistungsrechnen (Center for Information Services and +High-Performance Computing) at the Technical University of Dresden. + +We developed ppamltracer and ppamltracer-python as part of DARPA's +Probabilistic Programming for Advancing Machine Learning (PPAML) +project [2]. + +References: + [1] http://tu-dresden.de/zih/otf/ + [2] http://darpa.mil/Our_Work/I2O/Programs/Probabilistic_Programming_for_Advanced_Machine_Learning_(PPAML).aspx +""" +# TODO: Replace "ue" in "fuer" with Unicode u-with-diaresis (blocking on +# deployment of fix to Python #1065986, "Fix pydoc crashing on unicode +# strings"). + +import ctypes +import ctypes.util +import warnings + + +################################ Low-level API ################################ + +_lib = ctypes.cdll.LoadLibrary(ctypes.util.find_library("ppamltracer")) +"""ctypes binding to the ppamltracer C library.""" + +# The code in this section binds the C API using ctypes, translating +# return codes into the exception hierarchy defined below. Since these +# functions are not intended to be used externally, they're not +# documented using pydoc; see the ppamltracer C API documentation for +# information on their behavior. + +_sizeof_ppaml_tracer_t = \ + ctypes.c_size_t.in_dll(_lib, "ppaml_tracer_t_size").value + +_sizeof_ppaml_phase_t = ctypes.c_size_t.in_dll(_lib, "ppaml_phase_t_size").value + +def _ppaml_tracer_init(tracer, report_name_base): + result = _lib.ppaml_tracer_init(tracer, report_name_base) + if result == 0: + return None + elif result == 1: + raise OTFManagerInitializationError() + elif result == 2: + raise OTFWriterInitializationError() + elif result == 3: + raise OTFWriterResolutionError() + elif result == 4: + raise OTFWriterProcessDefinitionError("main") + else: + _warn_unexpected_return_code() + raise TracerError() + +def _ppaml_tracer_done(tracer): + result = _lib.ppaml_tracer_done(tracer) + if result == 0: + return None + elif result == 1: + raise OTFWriterCloseError() + else: + _warn_unexpected_return_code() + raise TracerError() + +def _ppaml_phase_init(tracer, phase, name): + result = _lib.ppaml_phase_init(tracer, phase, name) + if result == 0: + return None + elif result == 1: + raise OTFWriterPhaseDefinitionError() + else: + _warn_unexpected_return_code() + raise TracerError() + +def _ppaml_phase_start(phase): + result = _lib.ppaml_phase_start(phase) + if result == 0: + return None + elif result == 1: + raise ClockAcquisitionError() + elif result == 2: + raise OTFWriterEntryError() + else: + _warn_unexpected_return_code() + raise TracerError() + +def _ppaml_phase_stop(phase): + result = _lib.ppaml_phase_stop(phase) + if result == 0: + return None + elif result == 1: + raise ClockAcquisitionError() + elif result == 2: + raise OTFWriterExitError() + else: + _warn_unexpected_return_code() + raise TracerError() + +def _ppaml_phase_done(phase): + result = _lib.ppaml_phase_done(phase) + if result == 0: + return None + else: + _warn_unexpected_return_code() + raise TracerError() + + +############################# Resource-based API ############################## + +class Tracer(object): + """A tracer for programs, which records execution timing information. + + This class is designed to be used with Python's "with" statement-- e.g., + + with Tracer("/tmp/my_report") as tracer: + main(tracer) + + """ + + def __init__(self, report_name_base): + """Create a new tracer. + + The tracer will create an Open Trace Format report during program + execution. The multiple files of the report will all start with the + specified base name. + + """ + self._report_name_base = report_name_base + self._underlying = None + + def __enter__(self): + if self._underlying is None: + self._underlying = \ + ctypes.create_string_buffer(_sizeof_ppaml_tracer_t) + _ppaml_tracer_init(self._underlying, self._report_name_base) + return self + + def __exit__(self, *exception_info): + if self._underlying is not None: + _ppaml_tracer_done(self._underlying) + self._underlying = None + + def create_phase(self, name): + """Construct a Phase associated with this Tracer. + + This function is merely a convenience function; internally, it shells + out to the Phase constructor. + + """ + return Phase(self, name) + + +class Phase(object): + """A phase of computation traced by ppamltracer. + + This class is designed to be used with Python's "with" statement-- e.g., + + with Phase(tracer, "my phase") as phase: + with phase.running(): + do_stuff() + with phase.running(): + do_stuff_again() + + Note the double use of "with". The outer "with" manages the lifetime of + a Phase; the inner "with" actually starts and stops the phase timer. + + """ + + def __init__(self, tracer, name): + """Define a new phase tracked by a given tracer.""" + self._tracer = tracer + self._name = name + self._underlying = None + + def __enter__(self): + if self._underlying is None: + self._underlying = \ + ctypes.create_string_buffer(_sizeof_ppaml_phase_t) + _ppaml_phase_init( + self._tracer._underlying, + self._underlying, + self._name) + return self + + def __exit__(self, *exception_info): + if self._underlying is not None: + _ppaml_phase_done(self._underlying) + self._underlying = None + + def _start(self): + _ppaml_phase_start(self._underlying) + + def _stop(self): + _ppaml_phase_stop(self._underlying) + + def running(self): + """ Create a resource manager for the phase timer. + + This manager handles starting and stopping the phase, allowing you to + time operations by saying, e.g., + + with phase.running(): + do_stuff() + + """ + return _PhaseTimerManager(self) + + +class _PhaseTimerManager(object): + """Manage entry and exit from a Phase using the "with" statement.""" + + def __init__(self, phase): + self._phase = phase + + def __enter__(self): + self._phase._start() + + def __exit__(self, *exception_info): + self._phase._stop() + + +############################# Exception hierarchy ############################# + +class TracerError(Exception): + """A generic ppamltracer error.""" + pass + +class OTFError(TracerError): + """An error related to Open Trace Format input and output.""" + pass + +class OTFManagerError(OTFError): + """An error caused by the Open Trace Format manager.""" + pass + +class OTFManagerInitializationError(OTFManagerError): + """Failure to initialize the Open Trace Format manager.""" + + def __init__(self): + super.__init__( + self, + "could not initialize Open Trace Format file manager") + +class OTFWriterError(OTFError): + """An error caused by the Open Trace Format writer.""" + pass + +class OTFWriterInitializationError(OTFWriterError): + """Failure to initialize the Open Trace Format writer.""" + + def __init__(self): + super.__init__(self, "could not open Open Trace Format writer") + +class OTFWriterPhaseDefinitionError(OTFWriterError): + """Failure to define a phase. """ + + def __init__(self): + super.__init__(self, "could not define phase") + +class OTFWriterEntryError(OTFWriterError): + """Failure to record entry into a phase.""" + + def __init__(self): + super.__init__(self, "could not record phase start") + +class OTFWriterExitError(OTFWriterError): + """Failure to record exit from a phase.""" + + def __init__(self): + super.__init__(self, "could not record phase end") + +class OTFWriterCloseError(OTFWriterError): + """Failure to close the Open Trace Format writer.""" + + def __init__(self): + super.__init__(self, "could not close Open Trace Format writer") + +class OTFWriterResolutionError(OTFWriterError): + """Failure to set the tracer resolution.""" + + def __init__(self): + super.__init__(self, "could not set trace resolution") + +class OTFWriterProcessDefinitionError(OTFWriterError): + """Failure to define an Open Trace Format process.""" + + def __init__(self, process_name=None): + if process_name is None: + super.__init__(self, "could not define Open Trace Format process") + else: + super.__init__(self, + ("could not define Open Trace Format process \"" + + process_name + + "\"")) + +class TimingError(TracerError): + """An error related to system timers.""" + pass + +class ClockAcquisitionError(TimingError): + """A failure to get the current clock time.""" + + def __init__(self): + super.__init__(self, "could not get current time") + + +############################### Warnings ############################### + +class UnwrappedCErrorWarning(Warning): + """A warning indicating a failure to correctly wrap a C API.""" + pass + +def _warn_unexpected_return_code(): + warnings.warn(("Unexpected C return code\n" + + "*** This is a bug in ppamltracer-python! Report it to the maintainers."), + UnwrappedCErrorWarning, + 2) diff --git a/bindings/python/setup.py b/bindings/python/setup.py new file mode 100755 index 0000000..d8e9ec2 --- /dev/null +++ b/bindings/python/setup.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# setup.py -- distutils setup script for ppamltracer-python +# Copyright (C) 2013 Galois, Inc. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +# To contact Galois, complete the Web form at +# or write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, +# Oregon, 97204-1622. + +from distutils.core import setup + +setup(name="ppamltracer-python", + version="0.1.0", + description="ppamltracer Python bindings", + author="Benjamin Barenblat", + author_email="bbarenblat@galois.com", + classifiers=["Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU General Public License (GPL)", + "Topic :: Software Development :: Compilers"], + license="GPL", + py_modules=['ppamltracer']) diff --git a/bindings/racket/.gitignore b/bindings/racket/.gitignore new file mode 100644 index 0000000..9f3ac02 --- /dev/null +++ b/bindings/racket/.gitignore @@ -0,0 +1,16 @@ +# .gitignore for ppamltracer-racket -*- conf -*- + +# Bytecode +compiled/ +*.dep +*.zo + +# Scribble +manual/ +*.html +*.tex +*.pdf +racket.css +scribble.css +scribble-style.css +scribble-common.js diff --git a/bindings/racket/README b/bindings/racket/README new file mode 100644 index 0000000..b6c9d06 --- /dev/null +++ b/bindings/racket/README @@ -0,0 +1,11 @@ + ppamltracer-racket, v0.1.0 + +This package contains Racket bindings to ppamltracer. It requires Racket v5.2 +or later. + +Currently, this package is designed to be used as a collection; to install it, +you should type `raco link --name ppamltracer .'. (You may uninstall it with +`raco link --remove ppamltracer'.) + +To build the documentation, which contains a detailed example of use, you +should run `scribble ++xref-in setup/xref load-collections-xref manual.scrbl'. diff --git a/bindings/racket/main.rkt b/bindings/racket/main.rkt new file mode 100644 index 0000000..e4db143 --- /dev/null +++ b/bindings/racket/main.rkt @@ -0,0 +1,396 @@ +#lang racket/base +#| ppamltracer -- Racket bindings to ppamltracer +Copyright (C) 2013, 2014 Galois, Inc. + +This library is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This library is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this library. If not, see . + +To contact Galois, complete the Web form at +or write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, +Oregon, 97204-1622. |# + +(require (for-syntax racket/base + racket/syntax + (only-in racket/list drop-right) + (only-in racket/string string-join) + (only-in srfi/13 string-tokenize) + (only-in srfi/14 char-set char-set-complement) + srfi/26; hole notation + )) + +(require (rename-in ffi/unsafe [-> ~>]) + ffi/unsafe/define) +(require racket/contract) + +#| A shorthand for 'let-syntax-rule' with only one macro. For example, + + (let-syntax-rule (take-fst x y) x + (take-fst 'foo 'bar)) + +expands to + + 'foo +|# +(define-syntax-rule (let-syntax-rule (name . args) template body) + (let-syntax ([name (syntax-rules () [(_ . args) template])]) + body)) + +;; Convenience macro to instantiate an exception at the current location. +(define-syntax-rule (fail exception args ...) + (apply exception (list args ... (current-continuation-marks)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Low-level interface ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Load the library. +(define-ffi-definer define-ppamltracer (ffi-lib "libppamltracer")) + +#| We're going to model ppaml_tracer_t and ppaml_phase_t as abstract types by +having Racket treat them as buffers. These two symbols define how long those +buffers need to be. Ideally, they should be of type 'size_t', but Racket +doesn't have a size_t builtin, so we just use the largest C unsigned integer +type. |# +(define-ppamltracer ppaml_tracer_t_size _uint64) +(define-ppamltracer ppaml_phase_t_size _uint64) + +#| Define the struct types we're working with as buffer types. Instead of +mucking around with initializers and finalizers, which we can't seem to get +working correctly, we simply export an API which enforces proper resource +cleanup. |# +(define (make-buffer size) (make-ctype (_bytes o size) #f #f)) +(define _ppaml_tracer_t (make-buffer ppaml_tracer_t_size)) +(define _ppaml_phase_t (make-buffer ppaml_phase_t_size)) + +#| To help avoid passing structs of the wrong type in API internals, we'll +manipulate the structs as tagged pointers. |# +(define _tracer (_cpointer 'ppaml_tracer_t)) +(define _phase (_cpointer 'ppaml_phase_t)) + +;; Allocation functions for _tracer and _phase. +(define (malloc-tagged-pointer size-or-type tag) + (let ([result (malloc size-or-type 'atomic)]) + (cpointer-push-tag! result tag) + result)) +(define (malloc-_tracer) + (malloc-tagged-pointer _ppaml_tracer_t 'ppaml_tracer_t)) +(define (malloc-_phase) + (malloc-tagged-pointer _ppaml_phase_t 'ppaml_phase_t)) + +;; Import library functions. +(define-ppamltracer ppaml_tracer_init (_fun _tracer _path ~> _int)) +(define-ppamltracer ppaml_tracer_done (_fun _tracer ~> _int)) +(define-ppamltracer ppaml_phase_init (_fun _tracer _phase _string ~> _int)) +(define-ppamltracer ppaml_phase_done (_fun _phase ~> _int)) +(define-ppamltracer ppaml_phase_start (_fun _phase ~> _int)) +(define-ppamltracer ppaml_phase_stop (_fun _phase ~> _int)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Error handling ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +#| Convenience macro to create an exception. For example, + + (define-exception exn:fail:whatever) + +expands to + + (struct exn:fail:whatever exn:fail () + #:extra-constructor-name make-exn:fail:whatever + #:transparent) + +You can also call 'define-exception' with a message. Then, instead of creating +an extra binary make-prefixed constructor, 'define-exception' will create an +extra /unary/ make-prefixed constructor. All instances of the exception will +then have the same message. For example, + + (define-exception exn:fail:whatever "whatever happened!") + +expands to + + (struct exn:fail:whatever exn:fail () + #:transparent) + (define (make-exn:fail:whatever continuation-mark-set) + (exn:fail:whatever "whatever happened!" continuation-mark-set)) +|# +(define-syntax (define-exception stx) + (let ([#| Lifts a function which operates on data to operate on syntax + instead. |# + map-as-datum + (lambda (f stx) (datum->syntax stx (f (syntax->datum stx))))] + [#| Given an exception name (as a symbol), produces the conventional + super-exception. For instance, + + (take-base-exn 'exn:fail:whatever) + + expands to + + 'exn:fail + |# + take-base-exn + (compose1 string->symbol + (cut string-join <> ":") + (cut drop-right <> 1) + (cut string-tokenize <> (char-set-complement + (char-set #\:))) + symbol->string)]) + (syntax-case stx () + [(_ name) + (with-syntax ([base-name (map-as-datum take-base-exn #'name)] + [make-name (format-id stx "make-~a" #'name + #:source #'name)]) + #'(struct name base-name () + #:extra-constructor-name make-name + #:transparent))] + [(_ name message) + (with-syntax ([base-name (map-as-datum take-base-exn #'name)] + [make-name (format-id stx "make-~a" #'name + #:source #'name)]) + #'(begin + (struct name base-name () #:transparent) + (define (make-name continuation-mark-set) + (name message continuation-mark-set))))]))) + +#| Like define-exception, but does not create an extra make-prefixed +constructor at all. |# +(define-syntax (define-exception* stx) + (let ([map-as-datum + (lambda (f stx) (datum->syntax stx (f (syntax->datum stx))))] + [take-base-exn + (compose1 string->symbol + (cut string-join <> ":") + (cut drop-right <> 1) + (cut string-tokenize <> (char-set-complement + (char-set #\:))) + symbol->string)]) + (syntax-case stx () + [(_ name) + (with-syntax ([base-name (map-as-datum take-base-exn #'name)]) + #'(struct name base-name () #:transparent))]))) + +;;;;; Exception hierarchy ;;;;; + +(define-exception exn:fail:ppamltracer) + +(define-exception exn:fail:ppamltracer:otf) + +(define-exception exn:fail:ppamltracer:otf:manager) + +(define-exception exn:fail:ppamltracer:otf:manager:initialization + "could not initialize Open Trace Format file manager") + +(define-exception exn:fail:ppamltracer:otf:writer) + +(define-exception exn:fail:ppamltracer:otf:writer:initialization + "could not open Open Trace Format writer") + +(define-exception exn:fail:ppamltracer:otf:writer:phase-definition + "could not define phase") + +(define-exception exn:fail:ppamltracer:otf:writer:entry + "could not record phase start") + +(define-exception exn:fail:ppamltracer:otf:writer:exit + "could not record phase end") + +(define-exception exn:fail:ppamltracer:otf:writer:close + "could not close Open Trace Format writer") + +(define-exception exn:fail:ppamltracer:otf:writer:resolution + "could not set trace resolution") + +(define-exception* exn:fail:ppamltracer:otf:writer:process-definition) +(define (make-exn:fail:ppamltracer:otf:writer:process-definition + process-name + continuation-mark-set) + (exn:fail:ppamltracer:otf:writer:process-definition + (format "could not define Open Trace Format process ~v" process-name) + continuation-mark-set)) + +(define-exception exn:fail:ppamltracer:timing) + +(define-exception exn:fail:ppamltracer:timing:clock-acquisition + "could not get current time") + + +;;;;; Error-checked versions of library functions ;;;;; + +#| This macro makes checking C return codes trivial. Invocation is analogous +to that for the 'cond' form: + + (define some-function + (checked some-c-function + [0 'ok] + [1 (exn make-exn:fail:ppamltracer "bad data format")] + [-1 'ok])) + +This defines 'some-function' as a function taking an arbitrary number of +arguments. 'some-function', when invoked, will pass all its arguments to +'some-c-function'. If 'some-c-function' returns 0 or -1, then some-function +will evaluate successfully to whatever 'some-c-function' returned; if +'some-c-function' returns 1, though, 'some-function' will raise an +'exn:fail:ppamltracer' exception with the specified error message. + +If 'some-c-function' returns an unexpected value, 'some-function' will raise an +'exn:fail' noting the actual return value and declaring it a bug. |# +(define-syntax-rule (checked proc [expected consequence] ...) + (let-syntax-rule (cond-rhs result consequence-or-exception) + (if (eq? consequence-or-exception 'ok) + result + (raise consequence-or-exception)) + (lambda args + (let ([result (apply proc args)]) + (case result + [(expected) (cond-rhs result consequence)] + ... + [else (error (quote proc) + "unexpected return value ~v\n\ +This is a bug in ppamltracer! Report it to the maintainers." + result)]))))) + +(define ((as-void proc) . args) + (void (apply proc args))) + +(define ppaml-tracer-init + (as-void + (checked ppaml_tracer_init + [0 'ok] + [1 (fail make-exn:fail:ppamltracer:otf:manager:initialization)] + [2 (fail make-exn:fail:ppamltracer:otf:writer:initialization)] + [3 (fail make-exn:fail:ppamltracer:otf:writer:resolution)] + [4 (fail make-exn:fail:ppamltracer:otf:writer:process-definition + "main")]))) + +(define ppaml-tracer-done + (as-void + (checked ppaml_tracer_done + [0 'ok] + [1 (fail make-exn:fail:ppamltracer:otf:writer:close)]))) + +(define ppaml-phase-init + + (as-void + (checked ppaml_phase_init + [0 'ok] + [1 (fail make-exn:fail:ppamltracer:otf:writer:phase-definition)]))) + +(define ppaml-phase-start + (as-void + (checked ppaml_phase_start + [0 'ok] + [1 (fail make-exn:fail:ppamltracer:timing:clock-acquisition)] + [2 (fail make-exn:fail:ppamltracer:otf:writer:entry)]))) + +(define ppaml-phase-stop + (as-void + (checked ppaml_phase_stop + [0 'ok] + [1 (fail make-exn:fail:ppamltracer:timing:clock-acquisition)] + [2 (fail make-exn:fail:ppamltracer:otf:writer:exit)]))) + +(define ppaml-phase-done + (as-void + (checked ppaml_phase_done + [0 'ok]))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; High-level API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +#| The functions in this section comprise a relatively safe API for this +library--i.e., using them will help avoid resource leaks. Of course, Racket +gives you plenty of rope to hang yourself--you could, for instance, call/cc +your way back into the middle of some traced function. |# + +;; Predicates on '_tracer' and '_phase', to emulate declaration as structs. +(define (cpointer-with-tag? obj tag) + (and (cpointer? obj) + (cpointer-has-tag? obj tag))) +(define (tracer? obj) (cpointer-with-tag? obj 'ppaml_tracer_t)) +(define (phase? obj) (cpointer-with-tag? obj 'ppaml_phase_t)) + +#| Execute a procedure in an exception-safe environment such that its resources +are properly released upon exit. With the exception handling stripped away, + + (managed-execution resource initialize initialize-args proc finalize) + +evaluates to + + (begin (apply initialize (cons resource initialize-args)) + (proc resource) + (finalize resource)) +|# +(define (managed-execution resource initialize initialize-args proc finalize) + (apply initialize (cons resource initialize-args)) + (let ([result + (with-handlers + ([exn? (lambda (exn) + #| An exception occurred during the execution of 'proc'. + Clean up and re-throw. |# + (with-handlers + ([exn? (lambda (exn) + #| An exception occurred during cleanup! + We're already responding to an existing + exception, though, so just ignore it. |# + (void))]) + (finalize resource)) + (raise exn))]) + (proc resource))]) + (finalize resource) + result)) + +(define (call-with-tracer report-name-base proc) + (managed-execution (malloc-_tracer) + ppaml-tracer-init + (list report-name-base) + proc + ppaml-tracer-done)) + +(define (call-with-phase tracer phase-name proc) + (managed-execution (malloc-_phase) + (lambda (phase tracer name) + ;; Reorder arguments to fit C API. + (ppaml-phase-init tracer phase name)) + (list tracer phase-name) + proc + ppaml-phase-done)) + +(define (call-with-phase-running phase proc) + (managed-execution phase + ppaml-phase-start + '() + (lambda (ignored) (proc)) + ppaml-phase-stop)) + + +;;;;; Macro versions ;;;;; + +(define-syntax-rule (let/tracer [tracer report-name-base] body ...) + (call-with-tracer report-name-base (lambda (tracer) body ...))) + +(define-syntax-rule (let/phase tracer [phase phase-name] body ...) + (call-with-phase tracer phase-name (lambda (phase) body ...))) + +(define-syntax-rule (with-phase-running phase body ...) + (call-with-phase-running phase (lambda () body ...))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Module interface ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(provide + (contract-out [tracer? (-> any/c boolean?)] + [phase? (-> any/c boolean?)] + [call-with-tracer (parametric->/c [A] + (-> path-string? (-> tracer? A) A))] + [call-with-phase (parametric->/c [A] + (-> tracer? string? (-> phase? A) A))] + [call-with-phase-running (parametric->/c [A] + (-> phase? (-> A) A))]) + let/tracer + let/phase + with-phase-running) diff --git a/bindings/racket/manual.scrbl b/bindings/racket/manual.scrbl new file mode 100644 index 0000000..f27731b --- /dev/null +++ b/bindings/racket/manual.scrbl @@ -0,0 +1,181 @@ +#lang scribble/manual +@;{ manual.scrbl -- Scribble documentation for ppamltracer-racket +Copyright (C) 2013, 2014 Galois, Inc. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . + +To contact Galois, complete the Web form at +or write to Galois, Inc., 421 Southwest 6th Avenue, Suite 300, Portland, +Oregon, 97204-1622. } + +@(require (for-label racket/base + racket/sequence)) +@(require (for-label ppamltracer)) + +@title{ppamltracer} + +ppamltracer is a lightweight, portable tracing library designed for explicit instrumention of generated code. +If you're writing a compiler and need hard data on your optimizer's efficacy, ppamltracer is the library for you. +This Racket library provides a high-level API on top of the libppamltracer C API. + +ppamltracer's usage can be summed up in a couple lines: + +@racketblock[ +(require ppamltracer) +(let/tracer [tracer "/tmp/my_report"] + (let/phase tracer [phase "phase 1"] + (with-phase-running phase + (do-stuff))) + (let/phase tracer [phase "phase 2"] + (with-phase-running phase + (do-other-stuff)) + (with-phase-running phase + (do-yet-more-stuff)))) +] + +This creates a report with the total runtime of @racket[do-stuff] recorded as "phase 1" and the total runtime of @racket[do-other-stuff] and @racket[do-yet-more-stuff] combined as "phase 2". + +@secref{getting-started} contains a more lengthy example. + +ppamltracer writes trace logs in the @hyperlink["http://tu-dresden.de/zih/otf/"]{Open Trace Format}, a free and open standard developed by the Zentrum für Informationsdienste und Hochleistungsrechnen (Center for Information Services and High-Performance Computing) at the Technical University of Dresden. + +We developed ppamltracer as part of DARPA's @hyperlink["http://darpa.mil/Our_Work/I2O/Programs/Probabilistic_Programming_for_Advanced_Machine_Learning_(PPAML).aspx"]{Probabilistic Programming for Advancing Machine Learning} (PPAML) project. + + +@section[#:tag "getting-started"]{Getting Started} + +This basic example demonstrates using ppamltracer to trace two functions -- a factorial function and a Fibonacci number generator. + +@#reader scribble/comment-reader (racketblock +;; simple.rkt -- basic ppamltracer example +;; This file is in the public domain. + +(require racket/sequence) +(require ppamltracer) + +(define (fact phase n) + ;; Record that we're running inside the factorial phase. + (with-phase-running phase + ;; Compute the factorial. + (if (= n 0) + 1 + (* n (fact phase (- n 1)))))) + +(define (fib phase n) + ;; Record that we're running inside the Fibonacci phase. + (with-phase-running phase + ;; Compute the nth Fibonacci number. + (case n + [(0 1) n] + [else (+ (fib phase (- n 1)) (fib phase (- n 2)))]))) + +;; Start ppamltracer. +(let/tracer [tracer "/tmp/simple_report"] + ;; Register the factorial phase. + (let/phase tracer [phase "fact"] + ;; Print factorials. + (printf "Factorials: ") + (sequence-for-each (lambda (n) (printf "~a " (fact phase n))) + (in-range 40)) + (printf "\n")) + ;; Register the Fibonacci phase. + (let/phase tracer [phase "fib"] + ;; Print Fibonacci numbers. + (printf "Fibonacci numbers: ") + (sequence-for-each (lambda (n) (printf "~a " (fib phase n))) + (in-range 16)) + (printf "\n"))) +) + +@section{API in Depth} + +@defmodule[ppamltracer] + +@subsection{Tracers} + +ppamltracer is fundamentally a set of stateful operations; the @racket[tracer] data type holds the state ppamltracer needs to operate properly. + +@defproc[(tracer? [obj any/c]) + boolean?]{ + Evaluates to @racket[#t] if and only if @racket[obj] is a @racket[tracer]. +} + +@defproc[(call-with-tracer [report-name-base path-string?] + [proc (-> tracer? A)]) + A]{ + Creates a new @racket[tracer]. + The @racket[tracer] will save trace reports in Open Trace Format; all trace file paths will begin with @racket[report-name-base]. +} + +@defform[#:id let/tracer + #:literals (tracer) + (let/tracer [tracer report-name-base] body ...) + #:contracts ([report-name-base path-string?])]{ + Macro version of @racket[call-with-tracer]. + Equivalent to + + @racketblock[ + (call-with-tracer report-name-base (lambda (tracer) body ...)) + ] +} + +@subsection{Phases} + +A @racket[phase] represents a phase of execution about which the user wishes to gather timing statistics. + +@defproc[(phase? [obj any/c]) + boolean?]{ + Evaluates to @racket[#t] if and only if @racket[obj] is a @racket[phase]. +} + +@defproc[(call-with-phase [tracer tracer?] + [phase-name string?] + [proc (-> phase? A)]) + A]{ + Creates a new @racket[phase] attached to @racket[tracer] and named @racket[phase-name]. +} + +@defform[#:id let/phase + #:literals (phase) + (let/phase tracer [phase name] body ...) + #:contracts ([tracer tracer?] + [name string?])]{ + Macro version of @racket[call-with-phase]. + Equivalent to + + @racketblock[ + (call-with-phase tracer name (lambda (phase) body ...)) + ] +} + +@subsection{Tracing} + +@defproc[(call-with-phase-running [phase phase?] + [proc (-> A)]) + A]{ + Runs @racket[proc], associating information about its timing and execution with @racket[phase] in the trace report. + Should @racket[proc] throw an exception, @racket[call-with-phase-running] will stop tracing before propagating the exception up the stack. +} + +@defform[#:id with-phase-running + #:literals (phase) + (with-phase-running phase body ...) + #:contracts ([phase phase?])]{ + Macro version of @racket[call-with-phase-running]. + Equivalent to + + @racketblock[ + (call-with-phase-running phase (lambda () body ...)) + ] +} + -- cgit v1.2.3