The Computer Language
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
Pharo7.0.2 build: 152, commit: 890f474


Sat, 26 Oct 2019 17:57:13 GMT

MAKE:
cp /opt/src/pharo64-linux-stable/Pharo7.0.2-0-64bit-890f474.image knucleotide.pharo-5.pharo_run.image
cp /opt/src/pharo64-linux-stable/Pharo7.0.2-0-64bit-890f474.changes knucleotide.pharo-5.pharo_run.changes
ln -s /opt/src/pharo64-linux-stable/Pharo7.0-32bit-890f474.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: [FileStream fileIn: prog].

ImageCleaner cleanUpForRelease.
Smalltalk garbageCollect.
SmalltalkImage current snapshot: true andQuit: true.


/opt/src/pharo64-linux-stable/pharo -headless knucleotide.pharo-5.pharo_run.image Include/pharo/make.st knucleotide.pharo-5.pharo 2>/dev/null
cat Include/pharo/main.st

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



23.96s to complete and log all make actions

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

PROGRAM FAILED 


PROGRAM OUTPUT:

pthread_setschedparam failed: Operation not permitted
This VM uses a separate heartbeat thread to update its internal clock
and handle events.  For best operation, this thread should run at a
higher priority, however the VM was unable to change the priority.  The
effect is that heavily loaded systems may experience some latency
issues.  If this occurs, please create the appropriate configuration
file in /etc/security/limits.d/ as shown below:

cat <<END | sudo tee /etc/security/limits.d/pharo.conf
*      hard    rtprio  2
*      soft    rtprio  2
END

and report to the pharo mailing list whether this improves behaviour.

You will need to log out and log back in for the limits to take effect.
For more information please see
https://github.com/OpenSmalltalk/opensmalltalk-vm/releases/tag/r3732#linux
'Errors in script loaded from Include/pharo/main.st'
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 | ...
BenchmarksGame class>>knucleotideFrom:to:
BenchmarksGame class>>do:
UndefinedObject>>DoIt
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 ]
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 | self installSourceFile: reference ]...etc...
OrderedCollection>>do:
[ sourceFiles do: [ :reference | self installSourceFile: reference ] ] in STCommandLineHandler>>installSourceFiles in Block: [ sourceFiles do: [ :reference | self installSourc...etc...
BlockClosure>>ensure:
STCommandLineHandler>>installSourceFiles
STCommandLineHandler>>activate
STCommandLineHandler class(CommandLineHandler class)>>activateWith:
[ aCommandLinehandler activateWith: commandLine ] in PharoCommandLineHandler(BasicCommandLineHandler)>>activateSubCommand: in Block: [ aCommandLinehandler activateWith: commandLine ]
BlockClosure>>on:do:
PharoCommandLineHandler(BasicCommandLineHandler)>>activateSubCommand:
PharoCommandLineHandler(BasicCommandLineHandler)>>handleSubcommand
PharoCommandLineHandler(BasicCommandLineHandler)>>handleArgument:
[ self
	handleArgument:
		(self arguments
			ifEmpty: [ '' ]
			ifNotEmpty: [ :arguments | arguments first ]) ] in [ [ self
	handleArgument:
		(self arguments
			ifEmpty: [ '' ]
			ifNotEmpty: [ :arguments | arguments first ]) ]
	on: Exit
	do: [ :exit | 
		"If the command line is protected by password, we just exit the image because in non-headless mode the handleExit will let the image open. If the password protection is enabled, it is to avoid to let the access to the image."
		self class commandLinePasswordManager hasPasswordSet
			ifTrue: [ Smalltalk snapshot: false andQuit: true ].
		^ self handleExit: exit ] ] in PharoCommandLineHandler(BasicCommandLineHandler)>>activate in Block: [ self...