Open sonygod opened 5 years ago
String concatenation is quite bad for our targets. You get much better results by using StringBuf
. The question is if the compiler could detect patterns like this and rewrite them to StringBuf
automatically.
By the way, HL and hxcpp don't crash for me, they just take a really long time. I'm not seeing much of a memory increase in the process, so I don't know why you would experience crashes.
they just take a really long time.yes ,very long time =crash.
I've waited for long time to see the last result, but unfortunately, it's cost lots of CPU.
after use StringBuf, wow, it's only used 0ms.
package;
import StringBuf;
import sys.io.File;
/**
* ...
* @author sonygod
*/
class StringBufTest
{
static function main()
{
var s = "1234567890abcdefghijklmnopqrstuvwxyz";
var t = Date.now().getTime();
var str = new StringBuf();
for (i in 0...100000){
str.add(s);
}
trace(Date.now().getTime() - t);
trace(str.length);
File.saveContent("c:/test.txt", str.toString());
}
}
package;
import StringBuf;
/**
* ...
* @author sonygod
*/
class StringBufTest
{
static function main()
{
var s = "1234567890abcdefghijklmnopqrstuvwxyz";
var t = Date.now().getTime();
var str = new StringBuf();
for (i in 0...100000){
var x=s.split('').join(',');//after add this ,it's slow down again.
str.add(x);
}
trace(Date.now().getTime() - t);
trace(str.length);
}
}
@hughsando Could you check the most recent example with -D HXCPP_GC_GENERATIONAL
? It hangs on a clean compilation, and segfaults after compiling without the flag once.
This memory access pattern is pretty bad for hxcpp, with the split creating holes in memory that can't be filled by the retained join results. This confused hxcpp into thinking it did not need more memory, when it actually did. HXCPP_GC_MOVING is designed to help here, but it should be fixed either way now.
@sonygod im having the same issue, and as soon as i add the split()
back in, it gets ridiculously slow
@hughsando is this supposed to be resolved? cause im using haxe 4 release, hl 1.10, and its still terrible
The performance here looks good. Even with 1,000,000 iterations, hxcpp=1.6 seconds, hl.exe = 23.6s You might try using the git version of hxcpp and see if this makes a difference.
To clear up some potential confusion:
@ncannasse = HL target = slow here @hughsando = C++ target = not slow here
Also note that @Aurel300 will be working on GC improvements for HL which we plan to land in Haxe 4.1.
@hughsando - for 1,000,000 iterations 23.6 seconds is good?
On my ancient Macbook node does a million iterations in 480 milliseconds. You need to set your sights a bit higher mate
I was interested in Haxe because with HL/Neko it seems to straddle a middle ground between compile time and performance.
What I assumed was node was on one end, and would have the worst performance but no compile time. On the other end is a native C++ binary, which has the best performance, but longest compile time.
I assumed Haxe HL/Neko targets would sit in the middle of the two extremes, some compile time, better performance than node.
Turns out everything I thought about HL/Neko was wrong. For my purposes, (large loops with lots of string manipulation) Node is almost as fast as a C++ binary created by haxe, and makes HL/Neko look like an absolute joke.
Tbh Im a little disappointed cause I love Haxe in theory/principle.
For your use-case I'd focus on node. It's very well optimized for string manipulation and it will take a long time before HL can hope to compete with that.
@matthewjumpsoffbuildings
current version 4.0 benchmark of performance of hl or hxcpp is slower than nodejs ,it's fact!
Maybe we can give time and give confidence to Haxe team .
Yes, what this is really measuring here is GC performance. And node has many many man years of effort put into its GC. Hxcpp has quite a bit and HL does not have that much so there is nothing too surprising here.
For reference, on my older laptop, with 1000000 iterations: hxcpp = 1.36s and cppia = 1.39s so cppia gives a good compile time/performance tradoff. Again, there is not much drop between cppia and hxcpp because they are using the same garbage collection code, which is doing most of the work. Cppia is quite similar to HL, but without the hype.
One thing about GC limited string manipulation code is that it usually be significantly optimized with some effort, but this depends on the application.
@matthewjumpsoffbuildings please does not deduce the speed of one target for a single benchmark. There are always some specific cases were some targets will perform less good than others. That will not give a good estimate of the overall target performances at all
Especially in cases were a single benchmark has magnitude difference, it's not in general because the target is magnitude slower but because the specific implementation of the feature has a different algorithm that either has room for improvements or makes different trade-off that gives some bad results in some cases.
In case of HL, which I can speak, Strings are not implemented as linked lists (ropes) like in JS so they form a single compact block of memory. This makes String concatenation expensive : a + b will allocate a new String and copy both a and b Strings into it. Doing that many times is O(n2).
You might conclude that HL is less fast for quick String manipulation than JS, which is true, but that does not generalize to other things you might want to do with the target.
PS : reproducible cases were one target is slower than others are always welcome, they help us improve the platforms in the area where a lot of gain can be made.
Thanks for the info @ncannasse - I appreciate your point, however I was hoping to use Haxe for a command line tool that is almost entirely focused on large amounts of string manipulation.
I still love the idea of Haxe in theory, just a bit bummed about this particular thing... that and I wish the docs were better, but thats another story :P
Good thing about Haxe is that you can compile to any target (e.g. to nodejs) and choose the one, which serves your current task best.
@hughsando your test is difference between my test.
hxcpp still very slowly ,I can't reproduce your 1.6s
sys:ubuntu 18.04 cpu :16 cores mem:16G haxe:4.01 hxcpp:git version
haxe -cp ./ -main StringTest -cpp cpp -D HXCPP_GC_MOVING
root@ubuntu:~/test/cpp# haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git
You already have hxcpp version git installed.
Updating hxcpp version git ...
hxcpp was updated
Library hxcpp current version is now git
root@ubuntu:~/test/cpp# haxe -cp ./ -main StringTest -cpp cpp
Type not found : StringTest
root@ubuntu:~/test/cpp# cd ../
root@ubuntu:~/test# haxe -cp ./ -main StringTest -cpp cpp
haxelib run hxcpp Build.xml haxe -Dhaxe="4.1.0-rc.1" -Dhaxe3="1" -Dhaxe4="1" -Dhaxe_ver="4.100" -Dhxcpp_api_level="400" -Dhxcpp_smart_strings="1" -Dsource-header="Generated by Haxe 4.1.0-rc.1" -Dstatic="1" -Dtarget.name="cpp" -Dtarget.static="true" -Dtarget.sys="true" -Dtarget.threaded="true" -Dtarget.unicode="true" -Dtarget.utf16="true" -Dutf16="1" -I"./" -I"" -I"/usr/local/lib/haxe/extraLibs/" -I"/usr/local/share/haxe/extraLibs/" -I"/usr/local/bin/extraLibs/" -I"/usr/local/lib/haxe/std/cpp/_std/" -I"/usr/local/share/haxe/std/cpp/_std/" -I"/usr/local/bin/std/cpp/_std/" -I"/usr/local/lib/haxe/std/" -I"/usr/local/share/haxe/std/" -I"/usr/local/bin/std/"
root@ubuntu:~/test# cd cpp
root@ubuntu:~/test/cpp# ./StringTest
StringTest.hx:23: 60236.6118164062
root@ubuntu:~/test/cpp# cd ../
root@ubuntu:~/test# haxe -cp ./ -main StringTest -cpp cpp -D HXCPP_GC_MOVING
haxelib run hxcpp Build.xml haxe -DHXCPP_GC_MOVING="1" -Dhaxe="4.1.0-rc.1" -Dhaxe3="1" -Dhaxe4="1" -Dhaxe_ver="4.100" -Dhxcpp_api_level="400" -Dhxcpp_smart_strings="1" -Dsource-header="Generated by Haxe 4.1.0-rc.1" -Dstatic="1" -Dtarget.name="cpp" -Dtarget.static="true" -Dtarget.sys="true" -Dtarget.threaded="true" -Dtarget.unicode="true" -Dtarget.utf16="true" -Dutf16="1" -I"./" -I"" -I"/usr/local/lib/haxe/extraLibs/" -I"/usr/local/share/haxe/extraLibs/" -I"/usr/local/bin/extraLibs/" -I"/usr/local/lib/haxe/std/cpp/_std/" -I"/usr/local/share/haxe/std/cpp/_std/" -I"/usr/local/bin/std/cpp/_std/" -I"/usr/local/lib/haxe/std/" -I"/usr/local/share/haxe/std/" -I"/usr/local/bin/std/"
root@ubuntu:~/test# cd cpp
root@ubuntu:~/test/cpp# ./StringTest
StringTest.hx:23: 59342.0219726562
Link: StringBufTest
root@ubuntu:~/test# cd cpp
root@ubuntu:~/test/cpp# ls
Build.xml HxcppConfig.h include obj Options.txt src StringBufTest StringBufTest.hash StringTest StringTest.hash
root@ubuntu:~/test/cpp# ./StringBufTest
StringBufTest.hx:22: 159.102294921875
StringBufTest.hx:23: 7100000
root@ubuntu:~/test/cpp# ./StringBufTest
StringBufTest.hx:22: 169.566162109375
StringBufTest.hx:23: 7100000
Yes, I am not looking at "StringTest", but only "StringBufTest". If I understand your output here, it is showing 0.169 seconds which is around to what I get. The StringTest usage will not be optimised any more, since the real answer here is to use a StringBuf - this is basically why this class exits. You might be able to do something fancy with an abstract and "operator +=" to give almost the same syntax, and I guess node is doing something similar to this under the hood.
hashlink :crash neko :crash node:17ms hxcpp:crash php:crash