Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions entries/ikelaiah/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Iwan Kelaiah

An Entry to the One Billion Row Challenge in Object Pascal.

The approach I implemented here is simplistic.

- Sequentially read the measurement file.
- Populate a `TDictionary` with station names, min, max, count and sum; without storing all the temperature measurements.
- Use a custom comparer to sort the station and temperature statistics in a `TStringList`.
- Display the sorted measurements using a simple for loop.

## Getting Started

### Dependencies

* None. Only latest Free Pascal Compiler and Lazarus. You can get these easily by using [`https://github.com/LongDirtyAnimAlf/fpcupdeluxe/releases`](https://github.com/LongDirtyAnimAlf/fpcupdeluxe/releases).

### Compiling

* Open `OneBRC.lpi` using Lazarus.
* Hit `Ctrl + F9` to compile.

### Running the executable

```bash
$ ./OneBRC.exe -i your_measurements.txt
```

To time the execution, do the following.

```bash
$ time ./OneBRC.exe -i your_measurements.txt
```

## Help

To see flags, use `-h`.

```
$ ./OneBRC.exe -h
OneBRC -- An entry to the One Billion Row Challenge for Object Pascal

Usage: OneBRC [-h] [-v] [-i input_file]

-h | --help Show this help screen
-v | --version Show the version number
-i | --input-file <filename> Input text file to process.
Each row is one temperature measurement in the format <string: station name>;<double: measurement>
```

Use `-v` to check version.

```bash
$ ./OneBRC.exe -v
OneBRC version 1.0
```

## Authors

Iwan Kelaiah
[ikelaiah](https://github.com/ikelaiah)

## Version History

* 1.0
* Initial Release - Sequential approach.

## License

This project is licensed under the MIT License - see the LICENSE.md file for details

## Acknowledgments

Inspiration, code snippets, etc.

1. The FPC team, Lazarus team, fpcupdeluxe team, and other contributors.
- For providing a usable programming language and a usable ecosystem.
2. Gustavo 'Gus' Carreno.
- For making this happen.
- Borrowed Gus' approach to use `TCustomApplication` and using `unit`s properly
to make main code more readable.
- Borrowed and modified Gus' `WriteHelp` from the `baseline.lpr`.
3. Székely Balázs.
- Now I know what `Single` data type is!
- I borrowed the custom `TStringList` comparer from the `baseline` program.
4. Shraddha Agrawal - https://www.bytesizego.com/blog/one-billion-row-challenge-go.
- The advice for not storing measurements for each station in a data structure.
5. Arman Hajisafi - https://arman-hs.github.io
- Encouragements and inspirations.
78 changes: 78 additions & 0 deletions entries/ikelaiah/src/OneBRC.lpi
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<PathDelim Value="\"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="OneBRC"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<BuildModes>
<Item Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<Units>
<Unit>
<Filename Value="OneBRC.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="stopwatch.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="Stopwatch"/>
</Unit>
<Unit>
<Filename Value="weatherstation.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="WeatherStation"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="OneBRC"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<RelocatableUnit Value="True"/>
<Optimizations>
<OptimizationLevel Value="2"/>
</Optimizations>
</CodeGeneration>
<Linking>
<LinkSmart Value="True"/>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>
137 changes: 137 additions & 0 deletions entries/ikelaiah/src/OneBRC.lpr
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
program OneBRC;

{
==Credits==

1. The FPC team, Lazarus team, fpcupdeluxe team, and other contributors.
- For providing a usable programming language and a usable ecosystem.
2. Gustavo 'Gus' Carreno.
- For making this happen.
- Borrowed Gus' approach to use `TCustomApplication` and using `unit`s properly
to make main code more readable.
- Borrowed and modified Gus' `WriteHelp` from the `baseline.lpr`.
3. Székely Balázs.
- Now I know what `Single` data type is!
- I borrowed the custom `TStringList` comparer from the `baseline` program.
4. Shraddha Agrawal - https://www.bytesizego.com/blog/one-billion-row-challenge-go.
- The advice for not storing measurements for each station in a data structure.
5. Arman Hajisafi - https://arman-hs.github.io
- Encouragements and inspirations.
}

{$mode objfpc}{$H+}{$J-}{$modeSwitch advancedRecords}
{$codepage utf8}
//{$DEFINE DEBUG}

uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes,
SysUtils,
CustApp,
WeatherStation;

const
version = '1.0';

type

{ TOneBRC }

TOneBRC = class(TCustomApplication)
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure WriteHelp; virtual;
end;

{ TOneBRC }

procedure TOneBRC.DoRun;
var
ErrorMsg: string;
filename: string = '';
begin
// quick check parameters
ErrorMsg := CheckOptions('hvi:', ['help', 'version', 'input:']);
if ErrorMsg <> '' then
begin
// Commented out the default ShowException as the generated text is not user friendly.
// ShowException(Exception.Create(ErrorMsg));
WriteLn('Error: ', ErrorMsg);
WriteHelp;
Terminate;
Exit;
end;

// Parse h
if HasOption('h', 'help') then
begin
WriteHelp;
Terminate;
Exit;
end;

// Parse v
if HasOption('v', 'version') then
begin
WriteLn('OneBRC version ', version);
Terminate;
Exit;
end;

// Parse i
if HasOption('i', 'input') then
begin
filename := GetOptionValue('i', 'input');
end;

if (length(filename) < 4) then
begin
WriteLn('Input file seems invalid.');
WriteHelp;
Terminate;
Exit;
end;

// Start the main algorithm
WeatherStation.ProcessTempMeasurements(filename);

// stop program loop
Terminate;
end;

constructor TOneBRC.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
StopOnException := True;
end;

destructor TOneBRC.Destroy;
begin
inherited Destroy;
end;

procedure TOneBRC.WriteHelp;
begin
WriteLn('OneBRC -- An entry to the One Billion Row Challenge for Object Pascal');
WriteLn;
WriteLn('Usage: OneBRC [-h] [-v] [-i input_file]');
WriteLn;
WriteLn(' -h | --help Show this help screen');
WriteLn(' -v | --version Show the version number');
WriteLn(' -i | --input-file <filename> Input text file to process.');
WriteLn(' Each row is one temperature measurement in the format <string: station name>;<double: measurement>');
end;

var
Application: TOneBRC;
begin
Application := TOneBRC.Create(nil);
Application.Title := 'OneBRC';
Application.Run;
Application.Free;
end.
64 changes: 64 additions & 0 deletions entries/ikelaiah/src/stopwatch.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
unit Stopwatch;

{$mode objfpc}{$H+}{$J-}{$modeSwitch advancedRecords}

interface

uses
Classes, SysUtils;

procedure StartTimer;
procedure StopTimer;
procedure ResetTimer;
procedure DisplayTimer;

implementation

var
startTime: QWord = 0;
endTime: QWord = 0;
elapsedMilliseconds: QWord = 0;
hours, minutes, seconds, milliseconds: word;

procedure StartTimer;
begin
startTime := GetTickCount64;
end;

procedure StopTimer;
begin
endTime := GetTickCount64;
end;

procedure ResetTimer;
begin
startTime := 0;
endTime := 0;
elapsedMilliseconds := 0;
end;

procedure DisplayTimer;
begin

// Elapsed milliseconds
elapsedMilliseconds := endTime - startTime;

// Convert milliseconds to hours, minutes, seconds, and milliseconds
hours := elapsedMilliseconds div 3600000;
elapsedMilliseconds := elapsedMilliseconds mod 3600000;

minutes := elapsedMilliseconds div 60000;
elapsedMilliseconds := elapsedMilliseconds mod 60000;

seconds := elapsedMilliseconds div 1000;
milliseconds := elapsedMilliseconds mod 1000;

WriteLn;
WriteLn('------------------------------');
WriteLn('Elapsed time: ', hours, ' hours ', minutes, ' minutes ',
seconds, ' seconds ', milliseconds, ' milliseconds');
//WriteLn('Elapsed time: ', (endTime - startTime), ' ms');
end;


end.
Loading