MSK Software Development

Archive for January, 2010

Vector Arithmetic - Primitives Examples

by admin on Jan.31, 2010, under Smalltalk

As an example I want to show, how I write primitives to enhance the speed of vector arithmetic.

I created a new subclass of OSFloat: MSKOSFloat64Vector, which should be used as a n-dimensional vector. I also created a special class for single-precision vectors … but that’s another story. I just want to tell the story for the double-precision vectors - because they also have the same precision as the Float instances within VASmalltalk.

The main method for vector addition is a pure Smalltalk one. It has to prepare all information needed for the primitive. As you notice: the code generates always a new vector for the result of the addition, but the primitives will be able to use the receiver or the parameter “aVector” as the target also. This will increase the speed of computation, because “+” generates this result very often during calculation and most of the generated objects are thrown away - and remember my last posting ? Object Creation can be very time consuming !

+ aVector
  | newVector |
  newVector := self class new: self mskDimension.

  ^self
       primAddVector: self
       with: aVector
       into: newVector
       dimension: self mskDimension

The lower level method does only one thing: it calls the primitive:

primAddVector: first with: second into: target dimension: anInteger
  primitive: 'mskvectorextension.dll':MSKOSFloat32VectorAddition
  ^self primitiveFailed

And we see the order of the parameters:
* first vector
* second vector
* third vector for the result
* dimension of the vectors

Now we look at the primitive code:

EsUserPrimitive(MSKOSFloat64VectorAddition)
{
  U_32     dimension;
  U_32     rc;
  double   *firstFloat64Vector;
  double   *secondFloat64Vector;
  double   *targetFloat64Vector;

  "We search for the base address of the first vector ... we use an additional function, because this is stupid c-work within Smalltalk structures"
  firstFloat64Vector =   baseAddressForOSPtrObjects(EsPrimVMContext, EsPrimArgument(1));
  if (firstFloat64Vector == (double *)NULL)
    EsPrimFail(1, 1);

  "Same stuff for the second operand"
  secondFloat64Vector = baseAddressForOSPtrObjects(EsPrimVMContext, EsPrimArgument(2));
  if (secondFloat64Vector == (double *)NULL)
    EsPrimFail(1, 2);

  "... and for the target vector"
  targetFloat64Vector = baseAddressForOSPtrObjects(EsPrimVMContext, EsPrimArgument(3));
  if (targetFloat64Vector == (double *)NULL)
    EsPrimFail(1, 3);

  "And we need the number of values, the vectors are containing. We do not check, if all vectors have the same dimension. We assume it. We convert the value of the fourth parameter to an unsigned integer"
  rc = EsIntegerToI32(EsPrimArgument(4), &dimension);
  if (rc != EsPrimErrNoError)
    EsPrimFail(1, 4);

  "now we have all c-structures to do the actual computation - in a different 'normal' function - which would be callable by platform function"
  doFloat64VectorAddition( firstFloat64Vector, secondFloat64Vector, targetFloat64Vector, (unsigned int) dimension);

  "We put the result into the third parameter and we return this object as the result of this primitive"
  EsPrimSucceed( EsPrimArgument(3));
}

Now some code to find the base address of the OSFloat64Vector, where we may store the floating values. Please remember, that the memory is stored within Smalltalk memory or OS memory. The function must care about this.

void * baseAddressForOSPtrObjects(EsVMContext EsPrimVMContext,EsObject anObject)
{
  double   *float64;
  EsObject reference;
  EsObject offsetAndReftype;
  U_32     rc;
  U_32     referenceValue;
  U_32     offsetAndReftypeValue;

  // var inst index = 1 means attribute 'reference' of OSPtr instances
  reference = EsInstVarAt( anObject, 1);

  // var inst index = 2 means attribute 'offsetAndReftype' of OSPtr instances
  offsetAndReftype = EsInstVarAt( anObject, 2);

  // First we have to find out: Smalltalk memory or OS-based memory ...
  rc = EsIntegerToU32( offsetAndReftype, &offsetAndReftypeValue);
  if (rc != EsPrimErrNoError)
    return (double *) NULL;

  // = 1 means Smalltalk based memory and ByteArray in the attribute 'reference'
  if (offsetAndReftypeValue == 1)
  {
    // reference now points to an instance of ByteArray ... storage
    // therefore is in Smalltalk memory and we look for the address of
    // reference variable - which seams to be the start of the byte array
    float64 = (double *) EsInstVarAddr(reference);
  }
  else
    if (offsetAndReftypeValue == 2)
    {
      // reference now contains address of an OS memory, where the value
      // is stored
      rc = EsIntegerToU32( reference, &referenceValue);
      if (rc != EsPrimErrNoError)
        return (double *) NULL;

     // Why that ? Well Instantiations does this on the Smalltalk side also ....
      float64 = (double *) (referenceValue + (offsetAndReftypeValue >> 8)) ;
    }
    else
      return (double *) NULL;

  // return the pointer to the base address for storage of double precision floats ...
  return (void *) float64;
}

The computation of the vector addition is plain c code:

void doFloat64VectorAddition(double * firstFloat64Vector, double * secondFloat64Vector, double * targetFloat64Vector, unsigned int dimension)
{
  unsigned int index;
  for (index = 0 ; index < dimension ; index++)
  {
    *targetFloat64Vector = *firstFloat64Vector + *secondFloat64Vector;
    targetFloat64Vector++;
    firstFloat64Vector++;
    secondFloat64Vector++;
  }
}

I hope you get an idea, what you have to do to write your own primitive. Debugging is pretty worse - because you must have a debugger sitting on the DLL-entry point and going active, when Smalltalk calls your primitive, but I have not managed things like this. And problem is, that the primitive dll is locked when you call it for the first time. You have to exit VASmalltalk, recompile the library, exchange the library and start VASmalltalk again.

This topic is very new fo me and there may be bugs within this code - if you have suggestions, please let me know.

The Smalltalk source code for this extension is available at the VAST Goodies site and is named MSKVectorExtension.

In addition to this method there is also a vector-scalar multiplication, vector-subtraction and the accessing methods are primitive-enhanced - additional work will be done in the future.

The source code for the dll and the whole project is available at www.schrievkrom.de

Leave a Comment more...

Vector Arithmetic using Primitives

by admin on Jan.31, 2010, under Smalltalk

When we were talking about OpenGL we looked at other solutions and what you need is very simple: you need mostly 3-dimensional or 4-dimensional vectors - and these vectors are mainly given to the OpenAPI’s. Sometimes only one instance, but very often as vectors of OSFloat32 or OSFloat64.

These subclasses are well suited to be used as transfer instances for values to OpenGL - but they are worse, if you want to do heavy calculations with them.

These classes are also pretty well useable for vectors - and they give you the option to transfer values to os based memory.

But they are slow ….

Therefore people very often are using subclasses of Array to simulate vectors - and these solutions are pretty often the fastest available.

Therefore you have two possibilities:

* subclasses of OSStructure
* subclasses of Array

One of the worst problems of these classes are accessing: one-based index access when using Array and zero-based index access when using OSStructure solutions. That means, that code written for one solution is not suitable for the other one.

Regarding speed you may have a look at this picture shows benchmarks for vector addition:

benchmarks3

The upper lines show typical solutions of a vector addition using plain OSFloat32 classes in pure Smalltalk and typical code like:


array3 at: index put ((array1 at: index) + (array2 at: index))

The lines in the middle show solutions based on Arrays in pure Smalltalk. They show, that Array-based solutions are 3 times faster than the OSStructure-based solutions.

The lower lines show OSStructure solutions with a little help by primitives for float and doubles. These solutions are around 3 times faster than the Array based solutions and 10 times faster than the original OSStructure based solutions.

*Summary *

That means, that these primitive-supported solutions are the fastest solution and they are ideal suitable for transfering data to external C-API’s.

* Instance Creation is time consuming *

One additional word to the benchmarks - when building these benchmarks one can notice, that the creation of objects can be a pretty time consuming task. Therefore reusing of arrays might be a good idea to improve the speed of your application

Leave a Comment :, , , more...

Primitives or platform functions …

by admin on Jan.31, 2010, under Smalltalk

All modern Smalltalk implementations have a way to interact with functions written in other languages - at least when these other languages support c calling conventions.

The reasons for calling those external function may be needed to get additional functionality or better speed.

Under VASmalltalk we have two choices to call external c code.

* Platform Functions *

In this way you may call every external function in a known external dynamic link library - if it is callable using stdcall or cdecl calling convention. When writing those external libraries you are thinking in typical c structures and when using base datatypes like double, integers, strings or byte arrays (on the Smalltalk side) you also get them when calling the c function: double, integers or pointers to strings or the memory of byte arrays.

In VASmalltalk the class hierarchy under OSObject is very useful to manage the data transfer between Smalltalk and the external world - they look and feel like normal c structures.

* Primitives *

With primitives you may also call external functions in a known external dynamic link library, BUT when writing those functions your parameters from Smalltalk are the plain Smalltalk structures accessable via c-function/macros.

In the general case you will then have to navigate (using c functions) through the Smalltalk object structure and look for the values you may need. More or less you will extract the needed values, prepare them for c computing and then call an additional function like in the first case.

Having to deal with return values you have to create new Smalltalk objects (in c code) and those objects are returned to the Smalltalk world.

Writing primitives is very low level stuff and there must be good reasons to use primitives instead of platform functions calling.

* Why Primitives ? *

There may be reasons for using and writing primitives: speed. It takes 6 times longer to make an external function call than to call a primitive. In general this is not worth the additional problems of writing a primitive, but when you know, that these calls are made very frequently in your image then you should consider the stony way of writing your primitives - with limited support of debugging etc …

I have never seen the real need for a user to write primitives and therefore I never wrote primitives in the last 13 years (when I started working with VASmalltalk) - but after talking with another Smalltalker about the OpenGL interface for VA I did a closer look in this topic and after some bug fixes in the sample primitive example (thanks to John O’Keefe from Instantiations) I sat down and wrote my own primitive.

Leave a Comment :, , , , more...

Ship Viewing in Brokdorf und am Kanal

by admin on Jan.24, 2010, under Kleve und Umgebung

Ich habe mal die Filmmaterialien aufbereitet und veröffentlicht:

Queen Mary 2 in Hamburg und in Brokdorf:

Norwegian Dream im Nord-/Ostseekanal:

Leave a Comment more...

Stimmbezirk in Husum - Kopfschütteln angebracht ?

by admin on Jan.24, 2010, under Meinungen

Diese Fragen muss man sich stellen, wenn man das Ergebnis der Nachzählung in dem entsprechenden Wahlbezirk betrachtet. Wurde da nicht nachgezählt ? Da werden natürlich gleich die Befürworter der Wahlcomputer kommen - obwohl: dort könnte man überhaupt nicht nachzählen. Ist also eigentlich ein Argument gegen die Wahlcomputer …

Nun ja, die Regierungskoalition hat nur noch eine Stimme Mehrheit - ist ja alles kein Problem, aber man wird sehen, wie stark der Wille zur Macht und ist und was man dann alles akzeptiert.

Leave a Comment more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit our friends!

A few highly recommended friends...