6 ms·
I'm no C expert - too bad to hear that about his C code. However I can tell people here that Vector.Unboxed is a very common optimization as soon as you start t
by ozataman 14y ago
I'm no C expert - too bad to hear that about his C code. However I can tell people here that Vector.Unboxed is a very common optimization as soon as you start thinking about performance in Haskell. Nothing "expertly" about it, really. I, for one, use it in all of my computational Haskell code.
- zura 14y agoMy impression is that, while it is possible to come up with a performance oriented Haskell code, it becomes quite ugly and diverges from those beautiful and idiomatic examples found in books. E.g. explicit strictness specifications, real quicksort (with Array.ST), etc..
- Cowen 14y agoThat's actually the problem he's hinting at near the end as he's trying to make his point about optimizing C. The optimizations he needs to make to the C code didn't seem clear to him when he was writing it, but they're very common optimizations for someone with more experience writing in C. That he made the seemingly-natural optimization in Haskell while not affording C the same luxury is what's hurting his argument.
- cube13 14y ago"Haskell is easier to optimize than C" != "Haskell is faster than C".
- shrughes 14y agoAre you writing that in Haskell or in C? Because in Haskell, you'd want to use the /= operator. In C, you'd want to use strcmp.
- vajrabum 14y agoI think you meant strncmp. Nobody ever wants strcmp, not if they know what it does.
- tedunangst 14y agoYou don't know what you're talking about.
- shrughes 14y agoWe know what it does and it's the right thing to use. You must be thinking of strncpy or some other ennified string.h function.
- dllthomas 14y agoIf Haskell is easier to optimize than C, then it could easily be that there's some amount of programmer effort, for which expending that much effort in Haskell yields a faster program than expending that much effort in C. If that amount of effort is in the range of effort most people are able to expend on a class of projects, then Haskell is faster than C for those projects. It may even be that those are most projects. It is, of course, not the case that Haskell is faster than C with arbitrary effort expended tuning to the specific hardware - no one is claiming that.
- jlarocco 14y agoFair enough. My complaint is that the C code isn't given the same chance. He even calls out that reading data with getc is a known performance problem, but then does it anyway. Any book on learning C will point out that getc is slow for reading lots of data, and fscanf or fread should be used instead.
- alayne 14y agoI would never encourage use of the f* I/O functions from the standard C library for high performance code. They're all buffered which means there's an extra copy happening. You should use read and other POSIX I/O functions instead.
- jacquesm 14y agoThis is not 100% true. f* calls are buffered this is true. But depending on your workload this may be a blessing in disguise because if you're parsing a very long stream of unstructured data you'll have to re-implement most of that buffering logic in your own code to deal with the inevitable corner cases where your data overlaps the borders of the buffersize chosen. The obvious optimization here is to pre-allocate a buffer of the right size and read in the data in one go but for a stream of unknown and possibly infinite length (such as used in a filter like this) that is not possible. So f* function have their place, even in optimized code, but should be used with care. If you're reading data with fixed size blocks (such as in this example) then yes, a simple 'read' call will likely be faster, because as you note the read call will place the data directly into a user accessible buffer without the need to go through more library calls to get at the data. (fread is a wrapper function around the read system call).
- gnuvince 14y agoFrom what I understood from his post, using a buffered input function would a) make the code differ from the specification, b) require more refactoring than the Haskell code needed. b) seems particularly important when the program is not <100LOC, but tens or hundreds of lines of code.
- 14y ago
- jrockway 14y agoIt's also important to notice that Data.Vector.Unboxed has the same API as the other Data.Vector implementations and provides the same typechecking that the other implementations do. All it requires is that the underlying type have a Unbox instance. In most cases, you change: import Data.Vector as V to import Data.Vector.Unboxed as V and your code now gets the performance increase. (The reason it's not the default is because it's not most generic. What if you want to have a vector of IO computations? Good luck unboxing that. But if you just want integers, or something, that's much easier.)
- bcoates 14y agoIf they have the same semantics why doesn't the library do an unboxing implementation for types that support it and not for the rest?
- tedunangst 14y agoThis sounds like exactly the sort of optimization that I'm always hearing a sufficiently smart compiler will make for me.
- PaulAJ 14y agoNo, because compilers are prohibited from changing the meaning of the program. Changing a lazy value to a strict value is only permitted when the compiler can prove that the value will always be evaluated. It can't do that for unboxed arrays because that is a global change, so it has to leave it to the programmer.
- ramchip 14y agoThe semantics are different with regard to lazyness: a boxed vector can contain thunks (unevaluated values), so individual elements can be evaluated on demand, while an unboxed vector must be evaluated all at the same time (making it difficult to run a transformation in parallel with multiple threads, for example).