The Computer Language
23.03 Benchmarks Game

k-nucleotide Pharo Smalltalk #5 program

source code

"* The Computer Language Benchmarks Game
    https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
    contributed by Andres Valloud
    modified by Isaac Gouy for Pharo *"!

Object subclass: #BenchmarksGame
   instanceVariableNames: ''
   classVariableNames: ''
   poolDictionaries: ''
   category: ''!

!SequenceableCollection methodsFor: 'benchmarks game'!

substringFrequencies: aLength using: aDictionary
   | buffer |
   buffer := String new: aLength.
   1 to: self size - aLength + 1 do:
      [:i |
         | answer |
         buffer replaceFrom: 1 to: aLength with: self startingAt: i.
         answer := aDictionary
            at: buffer
            putValueOf: [:sum | sum + 1]
            ifAbsentPutValueOf: 1.
         answer = 1 ifTrue: [buffer := String new: aLength].
      ].
   ^aDictionary! !

!Dictionary methodsFor: 'benchmarks game'!

at: key putValueOf: putBlock ifAbsentPutValueOf: absentBlock
   "* Set the value at key to be the value of evaluating putBlock
    with the existing value. If key is not found, create a new
    entry for key and set is value to the evaluation of
    absentBlock. Answer the result of evaluating either block. *"

   | index element anObject |
   key == nil ifTrue:
      [^self
         subscriptBoundsErrorFor: #at:putValueOf:ifAbsentPutValueOf:
         index: key
         value: absentBlock value].
   index := self findElementOrNil: key.
   element := self basicAt: index.
   element == nil
      ifTrue: [self atNewIndex: index put:
         (self createKey: key value: (anObject := absentBlock value))]
      ifFalse: [element value: (anObject := putBlock value: element value)].
   ^anObject! !

!BenchmarksGame class methodsFor: 'private'!

readFasta: sequenceName from: input
   | sc gt lf prefix description buffer byte |
   sc := $; asciiValue.
   gt := $> asciiValue.
   lf := Character lf asciiValue.
   prefix := '>',sequenceName.

   "* find start of particular fasta sequence *"
   [(input atEnd) or: [
         (input peek = gt)
            ifTrue: [((line := (input upTo: lf) asString)
               findString: prefix) = 1]
            ifFalse: [input skipTo: lf. false].
          ]
   ] whileFalse.

   "* line-by-line read - it would be a lot faster to block read *"
   description := line.
   buffer := ReadWriteStream on: (String new: 1028).
   [(input atEnd) or: [(byte := input peek) = gt]] whileFalse: [
      (byte = sc)
         ifTrue: [input upTo: lf]
         ifFalse: [buffer nextPutAll: (input upTo: lf) asString]
      ].
   ^Association key: description value: buffer contents !

knucleotideFrom: input to: output
   "Same as av3, but create less strings while updating the frequencies"

   | sequence writeFrequencies writeCount |

   sequence := (self readFasta: 'THREE' from: input) value asUppercase.

   writeFrequencies :=
      [:k | | frequencies count |
      frequencies := SortedCollection sortBlock: [:a :b|
      (a value = b value) ifTrue: [b key < a key] ifFalse: [b value < a value]].

   count := 0.0.
   (sequence substringFrequencies: k using: (Dictionary new: 1024))
      associationsDo: [:each|
         frequencies add: each. count := count + each value].

   frequencies do: [:each | | percentage |
      percentage := (each value / count) * 100.0.
      output
         nextPutAll: each key; space;
         print: percentage digits: 3; nl]].

   writeCount := [:nucleotideFragment | | frequencies count |
      frequencies := sequence substringFrequencies: nucleotideFragment size
         using: (Dictionary new: 1024).
      count := frequencies at: nucleotideFragment ifAbsent: [0].
      output print: count; tab; nextPutAll: nucleotideFragment; nl].

   writeFrequencies value: 1. output nl.
   writeFrequencies value: 2. output nl.

   writeCount value: 'GGT'.
   writeCount value: 'GGTA'.
   writeCount value: 'GGTATT'.
   writeCount value: 'GGTATTTTAATT'.
   writeCount value: 'GGTATTTTAATTTATAGT'.! !


!BenchmarksGame class methodsFor: 'initialize-release'!

do: n
   self knucleotideFrom: Stdio stdin to: Stdio stdout! !

!Stream methodsFor: 'benchmarks game'!

print: number digits: decimalPlaces
   | precision rounded |
   decimalPlaces <= 0 ifTrue: [^ number rounded printString].
   precision := (10 raisedTo: decimalPlaces negated) asFloat.
   rounded := number roundTo: precision.
   self nextPutAll: 
      ((rounded asScaledDecimal: decimalPlaces) printString copyUpTo: $s)!

nl
   self nextPut: Character lf! !


!StdioStream instance methodsFor: 'positioning'!

skipTo: anObject 
   "Set the access position of the receiver to be past the next occurrence of 
   anObject. Answer whether anObject is found."

   [self atEnd]
      whileFalse: [self next = anObject ifTrue: [^true]].
   ^false! !



    

notes, command-line, and program output

NOTES:
64-bit Ubuntu quad core
Pharo 9.0.21
Dec 7 2022 20:44:42
Compiler: 5.4.0 20160609


Mon, 23 Jan 2023 18:16:41 GMT

MAKE:
cp /opt/src/pharo-vm-Linux-x86_64-stable/Pharo10-SNAPSHOT-64bit-2314c3f.image knucleotide.pharo-5.pharo_run.image
cp /opt/src/pharo-vm-Linux-x86_64-stable/Pharo10-SNAPSHOT-64bit-2314c3f.changes knucleotide.pharo-5.pharo_run.changes
ln -s /opt/src/pharo-vm-Linux-x86_64-stable/Pharo10.0-64bit-2314c3f.sources .
cat Include/pharo/make.st
| prog |

(SystemWindow windowsIn: World
      satisfying: [:w | w model canDiscardEdits])
   do: [:w | w delete].

   "load program to be measured"
prog := Smalltalk getSystemAttribute: 3.
(prog notNil) ifTrue: [prog asFileReference fileIn].

ImageCleaner cleanUpForRelease.
Smalltalk garbageCollect.
SmalltalkImage current snapshot: true andQuit: true.
/opt/src/pharo-vm-Linux-x86_64-stable/pharo --headless knucleotide.pharo-5.pharo_run.image Include/pharo/make.st knucleotide.pharo-5.pharo
NewUndeclaredWarning: BenchmarksGame class>>readFasta:from: (line is Undeclared)
NewUndeclaredWarning: BenchmarksGame class>>readFasta:from: (line is Undeclared)
cat Include/pharo/main.st

BenchmarksGame do: (Smalltalk getSystemAttribute: 3) asInteger.!
SmalltalkImage current snapshot: false andQuit: true!



27.41s to complete and log all make actions

COMMAND LINE:
/opt/src/pharo-vm-Linux-x86_64-stable/pharo --headless knucleotide.pharo-5.pharo_run.image Include/pharo/main.st 0 < knucleotide-input250000.txt

PROGRAM FAILED 


PROGRAM OUTPUT:

SubscriptOutOfBounds: 289
Dictionary(Object)>>errorSubscriptBounds:
Dictionary(Object)>>basicAt:
Dictionary>>at:putValueOf:ifAbsentPutValueOf:
ByteString(SequenceableCollection)>>substringFrequencies:using:
[:k | | frequencies count |
      frequencies := SortedCollection sortBlock: [:a :b|
      (a value = b value) ifTrue: [b key < a key] ifFalse: [b value < a value]].

   count := 0.0.
   (sequence substringFrequencies: k using: (Dictionary new: 1024))
      associationsDo: [:each|
         frequencies add: each. count := count + each value].

   frequencies do: [:each | | percentage |
      percentage := (each value / count) * 100.0.
      output
         nextPutAll: each key; space;
         print: percentage digits: 3; nl]] in BenchmarksGame class>>knucleotideFrom:to: in Block: [:k | | frequencies count |
      frequencies := S...etc...
BenchmarksGame class>>knucleotideFrom:to:
BenchmarksGame class>>do:
UndefinedObject>>DoIt
[ receiver withArgs: (context ifNil: [ #() ] ifNotNil: [ {context} ]) executeMethod: self compileDoit] in OpalCompiler>>evaluate in Block: [ receiver withArgs: (context ifNil: [ #() ] ifNot...etc...
FullBlockClosure(BlockClosure)>>on:do:
OpalCompiler>>evaluate
DoItChunk>>importFor:logSource:
[ :declaration |
		requestor ifNotNil: [
			requestor contents: declaration contents ].
		value := declaration importFor: requestor logSource: logSource  ] in CodeImporter>>evaluate in Block: [ :declaration |...
OrderedCollection>>do:
CodeImporter>>evaluate
[ codeImporter evaluate ] in STCommandLineHandler>>installSourceFile: in Block: [ codeImporter evaluate ]
FullBlockClosure(BlockClosure)>>on:do:
STCommandLineHandler>>handleErrorsDuring:reference:
STCommandLineHandler>>installSourceFile:
[ :reference | 
		self installSourceFile: reference ] in [ sourceFiles do: [ :reference | 
		self installSourceFile: reference ]
	] in STCommandLineHandler>>installSourceFiles in Block: [ :reference | ...
OrderedCollection>>do:
[ sourceFiles do: [ :reference | 
		self installSourceFile: reference ]
	] in STCommandLineHandler>>installSourceFiles in Block: [ sourceFiles do: [ :reference | ...
FullBlockClosure(BlockClosure)>>ensure:
STCommandLineHandler>>installSourceFiles
STCommandLineHandler>>activate
STCommandLineHandler class(CommandLineHandler class)>>activateWith:
[ aCommandLinehandler activateWith: commandLine ] in PharoCommandLineHandler(BasicCommandLineHandler)>>activateSubCommand: in Block: [ aCommandLinehandler activateWith: commandLine ]
FullBlockClosure(BlockClosure)>>on:do:
PharoCommandLineHandler(BasicCommandLineHandler)>>activateSubCommand:
PharoCommandLineHandler(BasicCommandLineHandler)>>handleSubcommand