Hi all,
1) could anyone explain me the difference between a canvas and a glist?
2) i would be nice to support Rewire, wouldn't it? I just realized that version 2.0 also supports MIDI, but apparently Propellerheads won't give a license to non-commercial projects.... does anyone know more of that?
greetings, Thomas
Forgot to post the changes tigital and I commited to CVS over the weekend:
- added/fixed some yuv code. this will be the last yuv_ stuff added and now we'll start rolling yuv into pix. altivec code has been started and that will make it into the yuv part of pix_ in the next month or so.
- fixed pix_gain yuv code. it doesn't crash and generally works
- fixed pix_texture so that it now actually passes texcoords to geos for non-power of two textures. it works as it should on OSX, but someone needs to double check the other platforms.
- changed the color channel order in GemPixUtil.h so ARGB colors are correct.
lots more to come...
cgc
I added some more yuv processing to pix_add, diff, multiply, and subtract. I'm not sure if it's possible for someone to check for functionality on Windows or Linux, but the compile needs to be checked at the very least. I don't think anything will go wrong, but you never know.
Also, what are people's thoughts on optimizing the code? For example, I rewrote, but haven't committed, the RGBA part of pix_gain to use ints rather than floats in the loop and it's twice as fast now on PPC. A lot can be done with the pix_ code in terms of optimization. Here's a breakdown of CPU use for various pix_gain functions on a 1ghz g4 processing DV_NTSC at 30fps:
pix_gain - original RGBA- 49% cpu use pix_gain - int rewrite RGBA - 24% pix_gain - yuv scalar - 14% cpu pix_gain - yuv altivec - 2% cpu
Obviously these results show that performance gains can be huge if certain optimizations are done. Is any one doing this for x86? I see that there are two MMX functions that someone added, are there plans for more? It's probably a good idea to put structures in place, up front, to make sure that code compiles across platforms and there are not crashes on various processors. Are #ifdefs enough at this point? We (tigital and myself) are trying to figure out the best way to get this altivec code into CVS and have it not impact the x86 side of things.
best cgc
Left out a paragraph that's now gone to the cut and paste gremlin, so i'll paraphrase:
Part of the point about the pix_gain illustration is not that altivec or my scalar code kick ass, but that the original pix_gain code could actually run faster than my changes on a different platform. There should be a fair amount of testing when these things are changed, for compatibility, stability, and performance. It's not possible for each developer to know the ins and outs of tweaking each and every platform and compiler, so some collaboration is necessary on the shape of the code.
Anyway I really just wanted to open up a discussion about making GEM really fly on all platforms. ;)
On a somewhat related note: Is there someone building a Windows version of the CVS? I have a win2k box with pre-CVS GEM and no compiler, and would like to check out how the CVS version runs on it.
best cgc
On Wed, 29 Jan 2003, chris clepper wrote:
Left out a paragraph that's now gone to the cut and paste gremlin, so i'll paraphrase:
Part of the point about the pix_gain illustration is not that altivec or my scalar code kick ass, but that the original pix_gain code could actually run faster than my changes on a different platform. There should be a fair amount of testing when these things are changed, for compatibility, stability, and performance. It's not possible for each developer to know the ins and outs of tweaking each and every platform and compiler, so some collaboration is necessary on the shape of the code.
Right. Generally I can say that moving to integer calculation will not do harm in any case (well at least not in terms of speed).
Write down you investivations about speed in some file on CVS, with instructions how you tested it. This way others can contribute and we get a picture of what runs where and how.
Anyway I really just wanted to open up a discussion about making GEM really fly on all platforms. ;)
On a somewhat related note: Is there someone building a Windows version of the CVS? I have a win2k box with pre-CVS GEM and no compiler, and would like to check out how the CVS version runs on it.
What about moving the build system to gcc on windows too. Should be possible, no ? I am probably going to try this out with pd in the next days.
Guenter
Write down you investivations about speed in some file on CVS, with instructions how you tested it. This way others can contribute and we get a picture of what runs where and how.
Having a log of performance tweaks, tips and tests is a good idea. This could be put in the pix dir as something like Pix_performance.txt...
On a somewhat related note: Is there someone building a Windows version of the CVS? I have a win2k box with pre-CVS GEM and no compiler, and would like to check out how the CVS version runs on it.
What about moving the build system to gcc on windows too. Should be possible, no ? I am probably going to try this out with pd in the next days.
It seems like it would indeed be possible. Does gcc require Cygwin or some type of Unix environment to be installed?
cgc
Guenter
Hallo,
chris clepper hat gesagt: // chris clepper wrote:
It seems like it would indeed be possible. Does gcc require Cygwin or some type of Unix environment to be installed?
gcc is a part of the Cygwin distribution, but there also is MinGW (Minimalist Gnu for W32, http://www.mingw.org/) that IIR doesn't require a full Unix-like environment. But I never used those, gcc comes built into my Linux system ;)
ciao
On Wed, 29 Jan 2003, chris clepper wrote:
Also, what are people's thoughts on optimizing the code? For example, I rewrote, but haven't committed, the RGBA part of pix_gain to use ints rather than floats in the loop and it's twice as fast now on PPC. A lot can be done with the pix_ code in terms of optimization. Here's a breakdown of CPU use for various pix_gain functions on a 1ghz g4 processing DV_NTSC at 30fps:
pix_gain - original RGBA- 49% cpu use pix_gain - int rewrite RGBA - 24% pix_gain - yuv scalar - 14% cpu pix_gain - yuv altivec - 2% cpu
Obviously these results show that performance gains can be huge if certain optimizations are done. Is any one doing this for x86? I see that there are two MMX functions that someone added, are there plans for more?
hi chris,
Your results are really impressive. I did some experiments to with the pix code on linux, and you are right that we can gain a lot by optimizing the code. I changed pix_add and others from float to integer. I have also done experiments with MMX (which, I have to admit, did not give the results I had hoped for, but maybe just because I did not really know what I was doing ).
At least we should get rid of float pixel processing on all platforms.
It's probably a good idea to put structures in place, up front, to make sure that code compiles across platforms and there are not crashes on various processors. Are #ifdefs enough at this point? We (tigital and myself) are trying to figure out the best way to get this altivec code into CVS and have it not impact the x86 side of things.
#ifdefs are ugly If it is in some way possible, we should come up with macro's or templates for common optimizable functions. (I think there was a message from Daniel about that).
If that is not possible, put the architecture dependend code in its own source file, and write a non-altivec version of the same code. Later someone may add the MMX version, but can concentrate on that instead of having to go through ifdefs.
Greetings,
Guenter
On Thu, 30 Jan 2003, guenter geiger wrote:
Hi. I thought it would be interesting to share our experiences on that topic...
At least we should get rid of float pixel processing on all platforms.
I am quite close to do the opposite: I started with support for only one (albeit big) integer type, and I now support three integer types, and I'm going to add float32 support eventually. The main things that are blocking me are that several int operators (%,&,|,^) are not available for floats in C, and have no obvious mapping to a simple expression (i expect those operations to be homomorphic, so that most patches that work in int16 get to work in float32 at once...)
I have also done experiments with MMX (which, I have to admit, did not give the results I had hoped for, but maybe just because I did not really know what I was doing ).
I have added MMX code to my software; the asm code is generated with a script. The results I get with int32 are slightly slower than GCC's non-MMX output, and I'm doing pretty close to my best. However with int16 and uint8 the MMX gets a certain percentage of improvement, though really not extraordinary... 30-40% ? maybe it's all the packet-handling going on around that makes the improvement appear less than it really is?
It's probably a good idea to put structures in place, up front, to
make sure that code compiles across platforms and there are not crashes on various processors. Are #ifdefs enough at this point? We (tigital and myself) are trying to figure out the best way to get this altivec code into CVS and have it not impact the x86 side of things.
I'm using function pointer tables. GridFlow contains a table of 888 pointers to functions, and the mmx code replaces 30 of those.
If it is in some way possible, we should come up with macro's or templates for common optimizable functions.
I was using macros for all of that before; now it's more of a mixture of macros and templates. Some macro definitions contain "template <class T>" in them and so on.
If that is not possible, put the architecture dependend code in its own source file, and write a non-altivec version of the same code.
This is exactly what I've done on my side of things. The C code is in base/number.c; the MMX-dependent source is cpu/mmx.rb, which is a script that generates cpu/mmx.asm containing the 30 functions, and cpu/mmx_loader.c that does the function-pointer table surgery.
________________________________________________________________ Mathieu Bouchard http://artengine.ca/matju
I have also done experiments with MMX (which, I have to admit, did not give the results I had hoped for, but maybe just because I did not really know what I was doing ).
I have added MMX code to my software; the asm code is generated with a script. The results I get with int32 are slightly slower than GCC's non-MMX output, and I'm doing pretty close to my best. However with int16 and uint8 the MMX gets a certain percentage of improvement, though really not extraordinary... 30-40% ? maybe it's all the packet-handling going on around that makes the improvement appear less than it really is?
i got some (at first glance) counterintuitive results using mmx in pdp too. i guess a lot of this strangeness has to do with memory bandwidth. simple operations like add or scale are not much faster than their scalar integer c counterparts. i did get a lot of speedup for the more compute intensive stuff like the biquad filters, iterated convolution and basicly anything that needs to do a lot of clipping. also i try to limit the data copying to a minimum in pdp, this seems to help too..
the general rule seems to be: keep your memory accesses local and your data size small: do as much as possible inside the pixel loop, or iterate several times over 1 scanline instead of the whole image.
tom
I have also done experiments with MMX (which, I have to admit, did not give the results I had hoped for, but maybe just because I did not really know what I was doing ).
I have added MMX code to my software; the asm code is generated with a script. The results I get with int32 are slightly slower than GCC's non-MMX output, and I'm doing pretty close to my best. However with int16 and uint8 the MMX gets a certain percentage of improvement, though really not extraordinary... 30-40% ? maybe it's all the packet-handling going on around that makes the improvement appear less than it really is?
i got some (at first glance) counterintuitive results using mmx in pdp too. i guess a lot of this strangeness has to do with memory bandwidth. simple operations like add or scale are not much faster than their scalar integer c counterparts. i did get a lot of speedup for the more compute intensive stuff like the biquad filters, iterated convolution and basicly anything that needs to do a lot of clipping. also i try to limit the data copying to a minimum in pdp, this seems to help too..
the general rule seems to be: keep your memory accesses local and your data size small: do as much as possible inside the pixel loop, or iterate several times over 1 scanline instead of the whole image.
These points seems to hold true for all SIMD types. Altivec is pretty much limited by memory bandwidth so it pays to do as much calculation on the data between memory accesses. In Altivec, there are also cache control functions to open up dedicated cache-lines to the vector unit, which help decrease memory load latencies. Maybe there exists something similar to this for MMX?
The structure of the processing chain is also a big factor. GEM is basically a chain of for loops, which probably isn't ideal, but it is quite flexible.
Matju, is GridFlow building a single loop and filling it with functions from a table? That seems like it could be really efficient, especially with the decrease in memory accesses between objects.
It's great that we are sharing all of these tips, findings and ideas, among developers working on various projects.
cgc
tom
the general rule seems to be: keep your memory accesses local and your data size small: do as much as possible inside the pixel loop, or iterate several times over 1 scanline instead of the whole image.
These points seems to hold true for all SIMD types. Altivec is pretty much limited by memory bandwidth so it pays to do as much calculation on the data between memory accesses. In Altivec, there are also cache control functions to open up dedicated cache-lines to the vector unit, which help decrease memory load latencies. Maybe there exists something similar to this for MMX?
iirc in both intel and amd extensions to mmx there are such instructions, but not compatible with each other..
The structure of the processing chain is also a big factor. GEM is basically a chain of for loops, which probably isn't ideal, but it is quite flexible.
Matju, is GridFlow building a single loop and filling it with functions from a table? That seems like it could be really efficient, especially with the decrease in memory accesses between objects.
hmm. instructions need to come from memory too ;) and most algo's need state data and this will fill up your data cache very fast. so swapping entirely to this method has the same problem as the "chain of loops" way.
but i agree that there should be a nice optimum somewhere in the middle. a while ago i've been looking for a way to parametrize all these factorizations to let an optimization program (i.e. genetic algo) descide on what is the best way to factor this. but i gave it up because it was a little more complex than i thought. however, there is a lot of research going on on this issue (data transfer and storage exploration at imec.be for instance..)
tom
On Thu, 30 Jan 2003, chris clepper wrote:
On Thu, 30 Jan 2003, Tom Schouten wrote:
i got some (at first glance) counterintuitive results using mmx in pdp too. i guess a lot of this strangeness has to do with memory bandwidth. simple operations like add or scale are not much faster than their scalar integer c counterparts.
You have to be careful to do the same optimisations in asm as in C code... I have done that mistake...
also i try to limit the data copying to a minimum in pdp, this seems to help too..
I haven't got to the point where data copying is really minimized in my software, but this task is much more of a challenge for me, as the data my objects accept are of wildly differing dimensions, so there's a clash between the strategies for handling small chunks and big chunks of data.
The structure of the processing chain is also a big factor. GEM is basically a chain of for loops, which probably isn't ideal, but it is quite flexible. Matju, is GridFlow building a single loop and filling it with functions from a table?
No, it is a packet-based system. A grid message contains the GridOutlet pointer of the sender; the receivers return their GridInlet pointers. Then the sender tells GridOutlet to send() or give(), which may buffer and/or send packets to the GridInlets. Then the GridInlets may slightly repacketize the data so that it comes in nice multiples of N (as specified by receivers for their own convenience...). And then object-specific code is called with a packet as a parameter... and so on...
In GridFlow there is a distinction between a "numeric operator" and a "grid operator". The former is really simple, it is a function that takes one or two arguments of a given number type (but actually every such operator comes with six differently vectorized versions of itself). The latter is quite complex code that may involve any number of nested for-loops in non-obviously-optimisable ways.
So what happens typically is that on a given chunk of data, a vectorized numeric operator is called, and then another is called, etc., in the midst of higher-level loops and memcpy()'s and so on. The result is that there is a lot of RAM access, *BUT* it is mostly at the cache level because of the packetizing.
That seems like it could be really efficient, especially with the decrease in memory accesses between objects.
I very well see myself adding a runtime machine code generator to GridFlow, which would take a few loop forms and fill-in the blanks. Right now, however, the strangest I've done is writing a script that generates GridFlow's _asm_ code. I still have to use the "nasm" program to convert to *.o and link it into gridflow.so ... And then I still have to figure out how that generator would fit with my processing model (I already have a few ideas)
This would be, of course, pentium-only (... for as long as I'm the only person working on GridFlow; i only have PC's)
________________________________________________________________ Mathieu Bouchard http://artengine.ca/matju
Your results are really impressive. I did some experiments to with the pix code on linux, and you are right that we can gain a lot by optimizing the code. I changed pix_add and others from float to integer. I have also done experiments with MMX (which, I have to admit, did not give the results I had hoped for, but maybe just because I did not really know what I was doing ).
MMX is only coded in asm right? That makes it that much harder for anyone who's not already an assembly expert. Altivec is at least C based functions and data types, but still tricky to learn. PDP is using some MMX on yuv pixels from the looks of it, maybe the results are better processing 16 bit pixels vs 32bit ones? There's always that huge range of SIMD options on x86 to pick from too: MMX,3DNow,SSE,SSE2, etc.
At least we should get rid of float pixel processing on all platforms.
That seems like a good idea. Type conversion in a big for loop isn't the most efficient thing to do. We can also check for division and branching in the loops, and try to eliminate those where possible. Do you know how things like loop unrolling help x86 platforms? There are some scalar tricks like that can be tried as well. The gcc on x86 seems to be far better at optimizing code than on PPC so maybe Linux is already getting a big boost by using a good compiler.
#ifdefs are ugly If it is in some way possible, we should come up with macro's or templates for common optimizable functions. (I think there was a message from Daniel about that).
If that is not possible, put the architecture dependend code in its own source file, and write a non-altivec version of the same code. Later someone may add the MMX version, but can concentrate on that instead of having to go through ifdefs.
#ifdefs _are ugly! Sometimes it's the only way, but there's probably a solution to adding in optimized code without tons of #ifdefs. Maybe one way is to add processRGBMMX, processYUVAltivec to the range of processing routines. It is possible to do a runtime architecture check for Altivec, is it possible for MMX? A check in GemPixObj could be made for these hardware features.
cgc
Greetings,
Guenter
MMX is only coded in asm right?
gcc has c extensions for mmx, but compared to the apple altivec ones, these look much worse than the plain assembly imho..
That makes it that much harder for anyone who's not already an assembly expert. Altivec is at least C based functions and data types, but still tricky to learn. PDP is using some MMX on yuv pixels from the looks of it, maybe the results are better processing 16 bit pixels vs 32bit ones?
to clear things up, pdp uses 24bit/pixel (96bit per 2x2 macropixel). 16 bit for the luma plane and 16 bit for 2x2 subsampled chroma planes. before release i did an 8 bit / component version (12bit/pixel) but it is too small if you want to do feedback stuff and want some headroom to play with. also since all mmx integer multiplications are 16bit, this cuts down on conversions..
I finally got 10.2 at work, but having a few little problems. Gem will not create a window:
Could not find valid pixel format AGL Full Screen: 640 x 480 MAC: no info.context error: GEM: Unable to create window error: GEM: gemwin: no window made On Wednesday, January 29, 2003, at 07:17 PM, chris clepper wrote:
info.context?
using pd 35-0 (non OSX specific)
Thanks Ben
Thomas Grill wrote:
- i would be nice to support Rewire, wouldn't it? I just realized that
version 2.0 also supports MIDI, but apparently Propellerheads won't give a license to non-commercial projects.... does anyone know more of that?
the website says: "Due to the legal aspects of the agreement you need to have a proper, registered company in order to qualify as a ReWire developer. We do not allow private persons, schools, or companies in other types of businesses, to become licensors."
only chance is that some company writes a commercial rewire plugin for pd or you make your own implementation of rewire. but maybe it's easier to write a vst plugin which connects two audio applications or a vst enabled application and pd.
there is an older article about rewire and vst in "sound on sound": http://www.sospubs.co.uk/sos/nov99/articles/rewire.htm
hi Thomas,
a 'canvas' is meant to be the contents (i.e. the 'glist') of an open patcher window. Since canvas' data structure is just a typedefed glist's one, you may substitute t_glist for t_canvas without a cast. In a way, they are same thing, as long as a glist is not gop. See glist_getcanvas() in g_graph.c.
Whether all this will be valid in 0.37 only Miller can tell...
Krzysztof
Thomas Grill wrote: ...
- could anyone explain me the difference between a canvas and a glist?