|
| 1 | +{-# LANGUAGE DataKinds #-} |
| 2 | +{-# LANGUAGE ImportQualifiedPost #-} |
| 3 | +{-# LANGUAGE OverloadedStrings #-} |
| 4 | +{-# LANGUAGE RecordWildCards #-} |
| 5 | +{-# LANGUAGE ScopedTypeVariables #-} |
| 6 | +{-# LANGUAGE TemplateHaskell #-} |
| 7 | +{-# OPTIONS_GHC -fplugin PlutusTx.Plugin #-} |
| 8 | +{-# OPTIONS_GHC -fplugin-opt PlutusTx.Plugin:target-version=1.1.0 #-} |
| 9 | + |
| 10 | +module Main where |
| 11 | + |
| 12 | +import Colourista (black, blueBg, bold, formattedMessage, greenBg, magentaBg) |
| 13 | +import Data.Text (Text) |
| 14 | +import Data.Text qualified as Text |
| 15 | +import Data.Text.IO qualified as Text |
| 16 | +import PlutusCore.Evaluation.Machine.ExBudget (ExBudget (..)) |
| 17 | +import PlutusCore.Evaluation.Machine.ExMemory (CostingInteger, ExCPU (..), ExMemory (..)) |
| 18 | +import PlutusTx qualified as Plinth |
| 19 | +import PlutusTx.BuiltinList (BuiltinList) |
| 20 | +import PlutusTx.BuiltinList qualified as BuiltinList |
| 21 | +import PlutusTx.Builtins (BuiltinArray, indexArray, sopListToArray, toOpaque) |
| 22 | +import PlutusTx.List qualified as SOP |
| 23 | +import PlutusTx.Test.Run.Code (EvalResult (..), displayExBudget, evaluateCompiledCode) |
| 24 | +import Text.Printf (printf) |
| 25 | +import Unsafe.Coerce (unsafeCoerce) |
| 26 | + |
| 27 | +-------------------------------------------------------------------------------- |
| 28 | +-- Plinth ---------------------------------------------------------------------- |
| 29 | + |
| 30 | +usesSopList :: Plinth.CompiledCode Integer |
| 31 | +usesSopList = |
| 32 | + $$(Plinth.compile [||lookupByIndex sopListOfInts||]) |
| 33 | + where |
| 34 | + lookupByIndex :: [Integer] -> Integer |
| 35 | + lookupByIndex xs = xs SOP.!! 99 |
| 36 | + |
| 37 | +usesBuiltinList :: Plinth.CompiledCode Integer |
| 38 | +usesBuiltinList = |
| 39 | + $$(Plinth.compile [||lookupByIndex (toOpaque sopListOfInts)||]) |
| 40 | + where |
| 41 | + lookupByIndex :: BuiltinList Integer -> Integer |
| 42 | + lookupByIndex xs = xs BuiltinList.!! 99 |
| 43 | + |
| 44 | +usesArray :: Plinth.CompiledCode Integer |
| 45 | +usesArray = |
| 46 | + $$(Plinth.compile [||lookupByIndex (sopListToArray sopListOfInts)||]) |
| 47 | + where |
| 48 | + lookupByIndex :: BuiltinArray Integer -> Integer |
| 49 | + lookupByIndex xs = indexArray xs 99 |
| 50 | + |
| 51 | +sopListConstruction :: Plinth.CompiledCode [Integer] |
| 52 | +sopListConstruction = $$(Plinth.compile [||sopListOfInts||]) |
| 53 | + |
| 54 | +builtinListConstruction :: Plinth.CompiledCode (BuiltinList Integer) |
| 55 | +builtinListConstruction = $$(Plinth.compile [||toOpaque sopListOfInts||]) |
| 56 | + |
| 57 | +builtinArrayConstruction :: Plinth.CompiledCode (BuiltinArray Integer) |
| 58 | +builtinArrayConstruction = $$(Plinth.compile [||sopListToArray sopListOfInts||]) |
| 59 | + |
| 60 | +{- FOURMOLU_DISABLE -} |
| 61 | +sopListOfInts :: [Integer] |
| 62 | +sopListOfInts = |
| 63 | + [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 |
| 64 | + ,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53 |
| 65 | + ,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78 |
| 66 | + ,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99 |
| 67 | + ] |
| 68 | +{- FOURMOLU_ENABLE -} |
| 69 | + |
| 70 | +builtinListOfInts :: BuiltinList Integer |
| 71 | +builtinListOfInts = toOpaque sopListOfInts |
| 72 | + |
| 73 | +-------------------------------------------------------------------------------- |
| 74 | +-- Main ------------------------------------------------------------------------ |
| 75 | + |
| 76 | +main :: IO () |
| 77 | +main = do |
| 78 | + let sopListConstructionResult = evaluateCompiledCode sopListConstruction |
| 79 | + sopListConstructionBudget = evalResultBudget sopListConstructionResult |
| 80 | + |
| 81 | + printHeader greenBg "Lookup in SOP List" |
| 82 | + let sopListTotalBudget = |
| 83 | + -- Total means construction + lookup |
| 84 | + evalResultBudget (evaluateCompiledCode usesSopList) |
| 85 | + sopListLookupBudget = |
| 86 | + sopListTotalBudget `subtractBudget` sopListConstructionBudget |
| 87 | + printBudget sopListLookupBudget |
| 88 | + |
| 89 | + let builtinListConstructionResult = |
| 90 | + evaluateCompiledCode builtinListConstruction |
| 91 | + builtinListConstructionBudget = |
| 92 | + evalResultBudget builtinListConstructionResult |
| 93 | + |
| 94 | + printHeader greenBg "Lookup in Builtin List" |
| 95 | + let builtinListLookupEvalResult = evaluateCompiledCode usesBuiltinList |
| 96 | + builtinListTotalBudget = |
| 97 | + evalResultBudget builtinListLookupEvalResult |
| 98 | + builtinListLookupBudget = |
| 99 | + builtinListTotalBudget `subtractBudget` builtinListConstructionBudget |
| 100 | + printBudget builtinListLookupBudget |
| 101 | + |
| 102 | + let arrayConstructionEvalResult = |
| 103 | + evaluateCompiledCode builtinArrayConstruction |
| 104 | + arrayConstructionBudget = |
| 105 | + evalResultBudget arrayConstructionEvalResult |
| 106 | + |
| 107 | + printHeader greenBg "Lookup in Builtin Array" |
| 108 | + let builtinArrayTotalEvalResult = evaluateCompiledCode usesArray |
| 109 | + builtinArrayTotalBudget = evalResultBudget builtinArrayTotalEvalResult |
| 110 | + builtinArrayLookupBudget = |
| 111 | + builtinArrayTotalBudget `subtractBudget` arrayConstructionBudget |
| 112 | + printBudget builtinArrayLookupBudget |
| 113 | + |
| 114 | + printHeader magentaBg "SOP List vs. Builtin List" |
| 115 | + printPercentage sopListLookupBudget builtinListLookupBudget |
| 116 | + |
| 117 | + printHeader magentaBg "SOP List vs. BuiltinArray" |
| 118 | + printPercentage sopListLookupBudget builtinArrayLookupBudget |
| 119 | + |
| 120 | + printHeader magentaBg "BuiltinList vs. BuiltinArray" |
| 121 | + printPercentage builtinListLookupBudget builtinArrayLookupBudget |
| 122 | + |
| 123 | + printHeader blueBg "Legend" |
| 124 | + putStrLn |
| 125 | + "A negative percentage indicates that \ |
| 126 | + \cost is lower on the right hand side of a comparison." |
| 127 | + putStrLn "\n" |
| 128 | + |
| 129 | +-------------------------------------------------------------------------------- |
| 130 | +-- Helper Functions ------------------------------------------------------------ |
| 131 | + |
| 132 | +printHeader :: Text -> Text -> IO () |
| 133 | +printHeader bg x = do |
| 134 | + putStrLn "" |
| 135 | + formattedMessage [bold, bg, black] (" " <> Text.strip x <> " ") |
| 136 | + |
| 137 | +printBudget :: ExBudget -> IO () |
| 138 | +printBudget = Text.putStrLn . displayExBudget |
| 139 | + |
| 140 | +printPercentage :: ExBudget -> ExBudget -> IO () |
| 141 | +printPercentage oldResult newResult = do |
| 142 | + let (cpuOld, memOld) = evalResultToCpuMem oldResult |
| 143 | + (cpuNew, memNew) = evalResultToCpuMem newResult |
| 144 | + putStr "CPU change: " |
| 145 | + putStrLn $ improvementPercentage cpuOld cpuNew |
| 146 | + putStr "MEM change: " |
| 147 | + putStrLn $ improvementPercentage memOld memNew |
| 148 | + where |
| 149 | + improvementPercentage :: Double -> Double -> String |
| 150 | + improvementPercentage old new = |
| 151 | + printf "%+.2f" ((new - old) / old * 100.0) <> " %" |
| 152 | + |
| 153 | + evalResultToCpuMem :: ExBudget -> (Double, Double) |
| 154 | + evalResultToCpuMem |
| 155 | + ExBudget |
| 156 | + { exBudgetCPU = ExCPU cpu |
| 157 | + , exBudgetMemory = ExMemory mem |
| 158 | + } = (toDouble cpu, toDouble mem) |
| 159 | + where |
| 160 | + toDouble :: CostingInteger -> Double |
| 161 | + toDouble x = fromIntegral (unsafeCoerce x :: Int) |
| 162 | + |
| 163 | +subtractBudget :: ExBudget -> ExBudget -> ExBudget |
| 164 | +subtractBudget |
| 165 | + ExBudget{exBudgetCPU = ExCPU cpu1, exBudgetMemory = ExMemory mem1} |
| 166 | + ExBudget{exBudgetCPU = ExCPU cpu2, exBudgetMemory = ExMemory mem2} = |
| 167 | + ExBudget (ExCPU (cpu1 - cpu2)) (ExMemory (mem1 - mem2)) |
0 commit comments