quickfix-developers Mailing List for QuickFIX (Page 233)
Brought to you by:
orenmnero
You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
|
Feb
(5) |
Mar
(16) |
Apr
(15) |
May
(17) |
Jun
(33) |
Jul
(35) |
Aug
(34) |
Sep
(19) |
Oct
(40) |
Nov
(51) |
Dec
(43) |
2003 |
Jan
(45) |
Feb
(79) |
Mar
(124) |
Apr
(121) |
May
(132) |
Jun
(77) |
Jul
(110) |
Aug
(57) |
Sep
(48) |
Oct
(83) |
Nov
(60) |
Dec
(40) |
2004 |
Jan
(67) |
Feb
(72) |
Mar
(74) |
Apr
(87) |
May
(70) |
Jun
(96) |
Jul
(75) |
Aug
(147) |
Sep
(128) |
Oct
(83) |
Nov
(67) |
Dec
(42) |
2005 |
Jan
(110) |
Feb
(84) |
Mar
(68) |
Apr
(55) |
May
(51) |
Jun
(192) |
Jul
(111) |
Aug
(100) |
Sep
(79) |
Oct
(127) |
Nov
(73) |
Dec
(112) |
2006 |
Jan
(95) |
Feb
(120) |
Mar
(138) |
Apr
(127) |
May
(124) |
Jun
(97) |
Jul
(103) |
Aug
(88) |
Sep
(138) |
Oct
(91) |
Nov
(112) |
Dec
(57) |
2007 |
Jan
(55) |
Feb
(35) |
Mar
(56) |
Apr
(16) |
May
(20) |
Jun
(77) |
Jul
(43) |
Aug
(47) |
Sep
(29) |
Oct
(54) |
Nov
(39) |
Dec
(40) |
2008 |
Jan
(69) |
Feb
(79) |
Mar
(122) |
Apr
(106) |
May
(114) |
Jun
(76) |
Jul
(83) |
Aug
(71) |
Sep
(53) |
Oct
(75) |
Nov
(54) |
Dec
(43) |
2009 |
Jan
(32) |
Feb
(31) |
Mar
(64) |
Apr
(48) |
May
(38) |
Jun
(43) |
Jul
(35) |
Aug
(15) |
Sep
(52) |
Oct
(62) |
Nov
(62) |
Dec
(21) |
2010 |
Jan
(44) |
Feb
(10) |
Mar
(47) |
Apr
(22) |
May
(5) |
Jun
(54) |
Jul
(19) |
Aug
(54) |
Sep
(16) |
Oct
(15) |
Nov
(7) |
Dec
(8) |
2011 |
Jan
(18) |
Feb
(9) |
Mar
(5) |
Apr
(5) |
May
(41) |
Jun
(40) |
Jul
(29) |
Aug
(17) |
Sep
(12) |
Oct
(23) |
Nov
(22) |
Dec
(11) |
2012 |
Jan
(8) |
Feb
(24) |
Mar
(5) |
Apr
(5) |
May
(6) |
Jun
(5) |
Jul
(5) |
Aug
(5) |
Sep
(2) |
Oct
(9) |
Nov
(2) |
Dec
(18) |
2013 |
Jan
(25) |
Feb
(16) |
Mar
(8) |
Apr
(2) |
May
(16) |
Jun
(17) |
Jul
(2) |
Aug
(13) |
Sep
(3) |
Oct
(4) |
Nov
(1) |
Dec
|
2014 |
Jan
(2) |
Feb
|
Mar
(22) |
Apr
(9) |
May
(3) |
Jun
(1) |
Jul
(5) |
Aug
(11) |
Sep
(18) |
Oct
(4) |
Nov
(4) |
Dec
(3) |
2015 |
Jan
(2) |
Feb
|
Mar
|
Apr
(3) |
May
(4) |
Jun
(37) |
Jul
|
Aug
(4) |
Sep
(6) |
Oct
(1) |
Nov
(4) |
Dec
(2) |
2016 |
Jan
(9) |
Feb
(3) |
Mar
(7) |
Apr
(1) |
May
(8) |
Jun
|
Jul
|
Aug
|
Sep
(7) |
Oct
(3) |
Nov
(16) |
Dec
|
2017 |
Jan
(1) |
Feb
(15) |
Mar
(2) |
Apr
(12) |
May
(4) |
Jun
(7) |
Jul
(5) |
Aug
|
Sep
|
Oct
|
Nov
(23) |
Dec
(8) |
2018 |
Jan
(2) |
Feb
(4) |
Mar
(2) |
Apr
(8) |
May
(3) |
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
2019 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(1) |
Sep
|
Oct
(5) |
Nov
(3) |
Dec
|
2020 |
Jan
|
Feb
(4) |
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
(12) |
Aug
(5) |
Sep
(3) |
Oct
(1) |
Nov
|
Dec
(1) |
2021 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
|
2022 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2025 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Joerg T. <Joe...@ma...> - 2004-08-17 21:09:52
|
Hi Jon, > How do you propose managing the two communication paths - one for > iLINK(tcp sockets) and one for MDAPI(tibco)? Actually, I do not know TIBCO, but Oren told me that somebody at CME -- obviously you -- used TIBCO to exchange FIX messages. How did you implement sending FIX messages over TIBCO? > Side note - I'm the developer who implemented the Order Entry Gateway for > the CME's Eurodollar Options System (EOS) > http://www.cme.com/abt/news/04-135EOSforEurodollars8295.html . > > We didn't modify one line of QF. We felt it was more than capable of > handling our requirements. Oren and the other developers have done an > excellent job and have been more than responsive to our needs. The week > long sessions are a plus to us and our customers. > > I wouldn't want more modifications to be made to QF which were specific to > the CME. QF is an implementation of the FIX protocol not iLINK(GLOBEX), > MDAPI or Tibco for that matter. [...] I fully agree, but I did not speak about changing QuickFIX, but providing extra access methods. Probably they would have to be kept separate from the normal package, since you probably need TIBCO libraries, header files and stuff to compile such access methods. In general, I think it would be nice to have such code in a "contrib" section. Cheers, Jörg >>QuickFIX Documentation: >>http://www.quickfixengine.org/quickfix/doc/html/index.html QuickFIX FAQ: >>http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ QuickFIX >>Support: http://www.quickfixengine.org/services.html >> >>Hi Richard, >> >> >>>I'm new to quickfix but it looks like a very promising solution to our >>>FIX needs. To be perfect it should have a TIBCO Rendezvous interface >>>to fit into our architecture. I read in the mailing lists that some of >>>you where/are working on this possibility. I would like to know if >>>anyone willing to share some of their code with me or do I need to >>>start from scratch ? >> >>Yes, I have discussed a TIBCO interface (TibcoSocketAcceptor and >>TibcoSocketInitiator) with Oren lately, since the Chicago Mercantile >>Exchange (www.cme.com) uses TIBCO and QuickFIX. Perhaps they give you >>some support in developing an open source TIBCO adapater. >> >>Cheers, Jörg >> >>-- >>Joerg Thoennes >> http://macd.com >>Tel.: +49 (0)241 44597-24 Macdonald Associates GmbH >>Fax : +49 (0)241 44597-10 Lothringer Str. 52, D-52070 Aachen >> >> >>------------------------------------------------------- >>SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media >>100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 >>Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. >>http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 >>_______________________________________________ >>Quickfix-developers mailing list >>Qui...@li... >>https://lists.sourceforge.net/lists/listinfo/quickfix-developers > > > -- Joerg Thoennes http://macd.com Tel.: +49 (0)241 44597-24 Macdonald Associates GmbH Fax : +49 (0)241 44597-10 Lothringer Str. 52, D-52070 Aachen |
From: Oren M. <or...@qu...> - 2004-08-17 20:55:57
|
Thanks. This has been fixed. --oren On Aug 16, 2004, at 5:56 AM, Brian wrote: > QuickFIX Documentation: > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > hi, > > i'm getting compilation errors on both FC1 and 2 on the > latest cvs version when i include --with-mysql. > > just thought you'd like to know before doing a release... > > brian > > > mysql-server-3.23.58-9 > mysql-3.23.58-9 > mysql-devel-3.23.58-9 > > > > g++ -DHAVE_CONFIG_H -I. -I. -I../.. -I. -I.. -I../.. -g -O2 -Wall > -I/usr/include/mysql -I/usr/include/libxml2 > -I/usr/java/j2sdk1.4.2_04/include > -I/usr/java/j2sdk1.4.2_04/include/linux -MT MySQLStore.lo -MD -MP -MF > .deps/MySQLStore.Tpo -c MySQLStore.cpp -fPIC -DPIC -o > .libs/MySQLStore.o > MySQLStore.cpp: In member function `void > FIX::MySQLStore::populateCache()': > MySQLStore.cpp:80: error: `m_session' undeclared (first use this > function) > MySQLStore.cpp:80: error: (Each undeclared identifier is reported only > once for > each function it appears in.) > MySQLStore.cpp:96: error: 'struct tm' has no member named 'tm_dst' > MySQLStore.cpp:112: error: `getValue' undeclared (first use this > function) > MySQLStore.cpp: In member function `virtual bool > FIX::MySQLStore::set(int, > const std::string&)': > MySQLStore.cpp:187: error: 'const struct std::basic_string<char, > std::char_traits<char>, std::allocator<char> >' has no member named > ' > getValue' > MySQLStore.cpp:198: error: `getValue' undeclared (first use this > function) > MySQLStore.cpp: In member function `virtual bool > FIX::MySQLStore::get(int, > std::string&) const': > MySQLStore.cpp:218: error: `getValue' undeclared (first use this > function) > MySQLStore.cpp: In member function `virtual void > FIX::MySQLStore::get(int, int, > std::vector<std::string, std::allocator<std::string> >&) const': > MySQLStore.cpp:244: error: `getValue' undeclared (first use this > function) > MySQLStore.cpp: In member function `virtual void > FIX::MySQLStore::setNextSenderMsgSeqNum(int)': > MySQLStore.cpp:280: error: `getValue' undeclared (first use this > function) > MySQLStore.cpp: In member function `virtual void > FIX::MySQLStore::setNextTargetMsgSeqNum(int)': > MySQLStore.cpp:297: error: `getValue' undeclared (first use this > function) > MySQLStore.cpp: In member function `virtual void > FIX::MySQLStore::reset()': > MySQLStore.cpp:334: error: `getValue' undeclared (first use this > function) > make[3]: *** [MySQLStore.lo] Error 1 > make[3]: Leaving directory `/home/brian/src2/quickfix/src/C++' > make[2]: *** [check-recursive] Error 1 > make[2]: Leaving directory `/home/brian/src2/quickfix/src/C++' > make[1]: *** [check-recursive] Error 1 > make[1]: Leaving directory `/home/brian/src2/quickfix/src' > make: *** [check-recursive] Error 1 > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Oren M. <or...@qu...> - 2004-08-17 20:33:08
|
I'm seeing a lot of similar reports on various message boards for other projects. The common thread is people who are using a very current version of libtool on Solaris 2.8 (a pattern you seem to match). Apparently how dynamic linking is done was radically changed sometime after libtool 1.4d. What is being said is that it has to do with is the visibility of const variables outside their translation units. So I guess there are three things you can try: 1) remove the const declarations that are causing the problems 2) run configure with --disable-shared 3) roll back your libtool to 1.4d or earlier As for the bootstrap problem, that is a Solaris specific bug in m4. You can learn more about it and how to fix it here: http://lists.gnu.org/archive/html/bug-m4/2004-07/msg00029.html --oren On Aug 17, 2004, at 1:11 PM, Tim Feeney wrote: > QuickFIX Documentation: > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > I tried to send this question to the users list but it was bounced > back. > > I have a Solaris 2.8 machine that I am trying to compile quickfix on. > Here is the setup > gcc - 3.4.1 > automake - 1.8.4 > libtool - 1.5 > autoconf - 2.59 > libxml2 - 2.6.9 > m4 - 1.4.1 > > I have an older version from a Mac that is running quickfix that fails > to compile giving me an error: > configure.in:14: /usr/local/bin/m4: ERROR: Reading inserted file: No > such file or directory > If I run bootstrap first on this build it also gives the same error. > > I downloaded the latest version to see if that was the problem but this > does not compile either. I get configure to run through with no > problems but when I then run make I get: > g++ -g -O2 -Wall -I/usr/local/include/libxml2 -I/include > -I/include/solaris -o .libs/at at.o C++/.libs/libquickfix.so > -L/usr/local/lib -L/usr/lib -L/usr/openwin/lib -L/usr/local/ssl/lib > /usr/local/lib/libstdc++.so > -L/usr2/SOURCES/S8/gcc-3.4.1/objdir/sparc-sun-solaris2.8/libstdc++-v3/ > src > -L/usr2/SOURCES/S8/gcc-3.4.1/objdir/sparc-sun-solaris2.8/libstdc++-v3/ > src/.libs > -L/usr2/SOURCES/S8/gcc-3.4.1/objdir/gcc > -L/usr/local/sparc-sun-solaris2.8/bin > -L/usr/local/sparc-sun-solaris2.8/lib > -L/usr/local/lib/../sparc-sun-solaris2.8/lib /usr/local/lib/libxml2.so > -lz -lpthread /usr/local/lib/libiconv.so -lm -lsocket -lnsl -liberty > -Wl,-R -Wl,/usr/local/lib > ld: warning: file /usr/local/lib/libstdc++.so: attempted multiple > inclusion of file > > If I run bootstrap I get the same message with regards to configure.in. > > I don't see anything in the list archives, so any hints/help from > people > that have gotten this to work? > > Tim > > > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Tim F. <ti...@fi...> - 2004-08-17 19:16:07
|
I tried to send this question to the users list but it was bounced back. I have a Solaris 2.8 machine that I am trying to compile quickfix on. Here is the setup gcc - 3.4.1 automake - 1.8.4 libtool - 1.5 autoconf - 2.59 libxml2 - 2.6.9 m4 - 1.4.1 I have an older version from a Mac that is running quickfix that fails to compile giving me an error: configure.in:14: /usr/local/bin/m4: ERROR: Reading inserted file: No such file or directory If I run bootstrap first on this build it also gives the same error. I downloaded the latest version to see if that was the problem but this does not compile either. I get configure to run through with no problems but when I then run make I get: g++ -g -O2 -Wall -I/usr/local/include/libxml2 -I/include -I/include/solaris -o .libs/at at.o C++/.libs/libquickfix.so -L/usr/local/lib -L/usr/lib -L/usr/openwin/lib -L/usr/local/ssl/lib /usr/local/lib/libstdc++.so -L/usr2/SOURCES/S8/gcc-3.4.1/objdir/sparc-sun-solaris2.8/libstdc++-v3/ src -L/usr2/SOURCES/S8/gcc-3.4.1/objdir/sparc-sun-solaris2.8/libstdc++-v3/ src/.libs -L/usr2/SOURCES/S8/gcc-3.4.1/objdir/gcc -L/usr/local/sparc-sun-solaris2.8/bin -L/usr/local/sparc-sun-solaris2.8/lib -L/usr/local/lib/../sparc-sun-solaris2.8/lib /usr/local/lib/libxml2.so -lz -lpthread /usr/local/lib/libiconv.so -lm -lsocket -lnsl -liberty -Wl,-R -Wl,/usr/local/lib ld: warning: file /usr/local/lib/libstdc++.so: attempted multiple inclusion of file If I run bootstrap I get the same message with regards to configure.in. I don't see anything in the list archives, so any hints/help from people that have gotten this to work? Tim |
From: Rich H. <rh...@ql...> - 2004-08-17 15:53:13
|
Isn't that backwards... application messages in fromApp and admin messages in fromAdmin? Cheers, Rich Oren Miller wrote: > QuickFIX Documentation: > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > Well, you are getting all the admin message in fromApp, and all the > application messages in fromAdmin. So you can just create a new method > and have both of these callbacks pass the parameters to that method. > > --oren > > On Aug 16, 2004, at 11:10 AM, Sharma Himanshu wrote: > >> QuickFIX Documentation: >> http://www.quickfixengine.org/quickfix/doc/html/index.html >> QuickFIX FAQ: >> http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ >> QuickFIX Support: http://www.quickfixengine.org/services.html >> >> Hi, >> >> I want to trap all messages(session + app) that come in the system at >> one central point. >> >> How can I do this? If not what is the next best method? >> >> Himanshu >> >> _________________________________________________________________ >> Claim your Citibank Ready Cash today. >> http://go.msnserver.com/IN/54177.asp It’s fast, easy and affordable. >> >> >> >> ------------------------------------------------------- >> SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media >> 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 >> Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. >> http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 >> _______________________________________________ >> Quickfix-developers mailing list >> Qui...@li... >> https://lists.sourceforge.net/lists/listinfo/quickfix-developers >> > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Joerg T. <Joe...@ma...> - 2004-08-17 08:12:50
|
Hi Richard, > I'm new to quickfix but it looks like a very promising solution to our FIX > needs. To be perfect it should have a TIBCO Rendezvous interface to fit > into our architecture. I read in the mailing lists that some of you > where/are working on this possibility. I would like to know if anyone > willing to share some of their code with me or do I need to start from > scratch ? Yes, I have discussed a TIBCO interface (TibcoSocketAcceptor and TibcoSocketInitiator) with Oren lately, since the Chicago Mercantile Exchange (www.cme.com) uses TIBCO and QuickFIX. Perhaps they give you some support in developing an open source TIBCO adapater. Cheers, Jörg -- Joerg Thoennes http://macd.com Tel.: +49 (0)241 44597-24 Macdonald Associates GmbH Fax : +49 (0)241 44597-10 Lothringer Str. 52, D-52070 Aachen |
From: <in...@ri...> - 2004-08-17 07:38:21
|
HI, I'm new to quickfix but it looks like a very promising solution to our FI= X needs. To be perfect it should have a TIBCO Rendezvous interface to fit into our architecture. I read in the mailing lists that some of you where/are working on this possibility. I would like to know if anyone willing to share some of their code with me or do I need to start from scratch ? Thanks, Richard |
From: Oren M. <or...@qu...> - 2004-08-16 18:09:57
|
Well, you are getting all the admin message in fromApp, and all the=20 application messages in fromAdmin. So you can just create a new method=20= and have both of these callbacks pass the parameters to that method. --oren On Aug 16, 2004, at 11:10 AM, Sharma Himanshu wrote: > QuickFIX Documentation:=20 > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ:=20 > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > Hi, > > I want to trap all messages(session + app) that come in the system at=20= > one central point. > > How can I do this? If not what is the next best method? > > Himanshu > > _________________________________________________________________ > Claim your Citibank Ready Cash today. =20 > http://go.msnserver.com/IN/54177.asp It=92s fast, easy and affordable. > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Sharma H. <sha...@ho...> - 2004-08-16 16:10:40
|
Hi, I want to trap all messages(session + app) that come in the system at one central point. How can I do this? If not what is the next best method? Himanshu _________________________________________________________________ Claim your Citibank Ready Cash today. http://go.msnserver.com/IN/54177.asp Its fast, easy and affordable. |
From: Brian <bri...@du...> - 2004-08-16 10:56:56
|
hi, i'm getting compilation errors on both FC1 and 2 on the latest cvs version when i include --with-mysql. just thought you'd like to know before doing a release... brian mysql-server-3.23.58-9 mysql-3.23.58-9 mysql-devel-3.23.58-9 g++ -DHAVE_CONFIG_H -I. -I. -I../.. -I. -I.. -I../.. -g -O2 -Wall -I/usr/include/mysql -I/usr/include/libxml2 -I/usr/java/j2sdk1.4.2_04/include -I/usr/java/j2sdk1.4.2_04/include/linux -MT MySQLStore.lo -MD -MP -MF .deps/MySQLStore.Tpo -c MySQLStore.cpp -fPIC -DPIC -o .libs/MySQLStore.o MySQLStore.cpp: In member function `void FIX::MySQLStore::populateCache()': MySQLStore.cpp:80: error: `m_session' undeclared (first use this function) MySQLStore.cpp:80: error: (Each undeclared identifier is reported only once for each function it appears in.) MySQLStore.cpp:96: error: 'struct tm' has no member named 'tm_dst' MySQLStore.cpp:112: error: `getValue' undeclared (first use this function) MySQLStore.cpp: In member function `virtual bool FIX::MySQLStore::set(int, const std::string&)': MySQLStore.cpp:187: error: 'const struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >' has no member named ' getValue' MySQLStore.cpp:198: error: `getValue' undeclared (first use this function) MySQLStore.cpp: In member function `virtual bool FIX::MySQLStore::get(int, std::string&) const': MySQLStore.cpp:218: error: `getValue' undeclared (first use this function) MySQLStore.cpp: In member function `virtual void FIX::MySQLStore::get(int, int, std::vector<std::string, std::allocator<std::string> >&) const': MySQLStore.cpp:244: error: `getValue' undeclared (first use this function) MySQLStore.cpp: In member function `virtual void FIX::MySQLStore::setNextSenderMsgSeqNum(int)': MySQLStore.cpp:280: error: `getValue' undeclared (first use this function) MySQLStore.cpp: In member function `virtual void FIX::MySQLStore::setNextTargetMsgSeqNum(int)': MySQLStore.cpp:297: error: `getValue' undeclared (first use this function) MySQLStore.cpp: In member function `virtual void FIX::MySQLStore::reset()': MySQLStore.cpp:334: error: `getValue' undeclared (first use this function) make[3]: *** [MySQLStore.lo] Error 1 make[3]: Leaving directory `/home/brian/src2/quickfix/src/C++' make[2]: *** [check-recursive] Error 1 make[2]: Leaving directory `/home/brian/src2/quickfix/src/C++' make[1]: *** [check-recursive] Error 1 make[1]: Leaving directory `/home/brian/src2/quickfix/src' make: *** [check-recursive] Error 1 |
From: Peterson, K. <kri...@rb...> - 2004-08-16 10:10:08
|
Comparing FieldConvertors.h from 1.7.1 to FieldConvertors.h from the source= I checked out from CVS a few days, the only changes I see are relate to th= rowing objects rather than references, adding a typedef for UtcDateOnlyConv= ertor, tm_isdst =3D -1 and #including Utility.h. As the conversion classes are used everytime and everywhere a field is conv= erted to/from a string, optimizations to the *Convertor classes should affe= ct performance throughout. Once I get the automake/conf/etc. tools up and running, I'll rerun these te= sts against a CVS build. - Kris=20 -----Original Message----- From: Oren Miller [mailto:or...@qu...] Sent: 13 August 2004 16:54 To: Peterson, Kristofer Cc: QuickFIX Development (E-mail) Subject: Re: [Quickfix-developers] FieldConvertor.h optimizations BTW those comparisons are against what was in the repository, which may =20 have something to do with it. They were already optimized a great deal =20 from 1.7.1. But I'm still not sure why the double conversions didn't =20 improve since that was unchanged from 1.7.1 --oren On Aug 12, 2004, at 2:13 PM, Peterson, Kristofer wrote: > QuickFIX Documentation: =20 > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: =20 > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > I have optimized some of the field convertors in FieldConvertors.h and = > have achieved substantial improvements in performance (generally 50% - = > 200% faster). I include a patch against the FieldConvertors.h file =20 > from quickfix-1.7.1. > > The code is admittedly 'C-ish', however no interface has been changed =20 > and I believe the results speak for themselves. > > Replacing strtod() in the double to string conversion would probably =20 > be a significant win, although I don't know of any efficient =20 > algorithms for this conversion. > > Finally, time stamp conversions should probably be added to pt as well. > > Cheers, > > - Kris > > The times were obtained from pt running on an AthlonXP 2500 running =20 > Linux kernel 2.6.7 compiled with g++ 3.3.4. 'normal' builds used the =20 > existing FieldConvertors.h, 'modified' builds used the modified =20 > FieldConvertors.h. > > Optimization flags for the builds were as follows: > > quickfix-debug-modified/Makefile:CFLAGS =3D -g -Wall > quickfix-debug-normal/Makefile:CFLAGS =3D -g -Wall > quickfix-optimized-modified/Makefile:CFLAGS =3D -g -O3 -ffast-math =20 > -mcpu=3Dathlon-xp -Wall > quickfix-optimized-normal/Makefile:CFLAGS =3D -g -O3 -ffast-math =20 > -mcpu=3Dathlon-xp -Wall > > times-debug-normal.txt : peterson@karl src $ ./pt -c 100000 > times-debug-modified.txt : peterson@karl src $ ./pt -c 100000 > times-optimized-normal.txt : peterson@karl src $ ./pt -c 100000 > times-optimized-modified.txt: peterson@karl src $ ./pt -c 100000 > > : Converting integers to strings: > times-debug-normal.txt : num: 100000, seconds: 0.259, =20 > num_per_second: 386100 > times-debug-modified.txt : num: 100000, seconds: 0.032, =20 > num_per_second: 3.125e+06 > times-optimized-normal.txt : num: 100000, seconds: 0.183, =20 > num_per_second: 546448 > times-optimized-modified.txt: num: 100000, seconds: 0.026, =20 > num_per_second: 3.84615e+06 > : Converting strings to integers: > times-debug-normal.txt : num: 100000, seconds: 0.024, =20 > num_per_second: 4.16667e+06 > times-debug-modified.txt : num: 100000, seconds: 0.008, =20 > num_per_second: 1.25e+07 > times-optimized-normal.txt : num: 100000, seconds: 0.016, =20 > num_per_second: 6.25e+06 > times-optimized-modified.txt: num: 100000, seconds: 0.004, =20 > num_per_second: 2.5e+07 > : Converting doubles to strings: > times-debug-normal.txt : num: 100000, seconds: 0.711, =20 > num_per_second: 140647 > times-debug-modified.txt : num: 100000, seconds: 0.243, =20 > num_per_second: 411523 > times-optimized-normal.txt : num: 100000, seconds: 0.531, =20 > num_per_second: 188324 > times-optimized-modified.txt: num: 100000, seconds: 0.236, =20 > num_per_second: 423729 > : Converting strings to doubles: > times-debug-normal.txt : num: 100000, seconds: 0.987, =20 > num_per_second: 101317 > times-debug-modified.txt : num: 100000, seconds: 0.058, =20 > num_per_second: 1.72414e+06 > times-optimized-normal.txt : num: 100000, seconds: 0.725, =20 > num_per_second: 137931 > times-optimized-modified.txt: num: 100000, seconds: 0.062, =20 > num_per_second: 1.6129e+06 > : Creating Heartbeat messages: > times-debug-normal.txt : num: 100000, seconds: 1.823, =20 > num_per_second: 54854.6 > times-debug-modified.txt : num: 100000, seconds: 1.166, =20 > num_per_second: 85763.3 > times-optimized-normal.txt : num: 100000, seconds: 1.242, =20 > num_per_second: 80515.3 > times-optimized-modified.txt: num: 100000, seconds: 0.825, =20 > num_per_second: 121212 > : Serializing Heartbeat messages to =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 2.35, =20 > num_per_second: 42553.2 > times-debug-modified.txt : num: 100000, seconds: 1.198, =20 > num_per_second: 83472.5 > times-optimized-normal.txt : num: 100000, seconds: 1.425, =20 > num_per_second: 70175.4 > times-optimized-modified.txt: num: 100000, seconds: 0.707, =20 > num_per_second: 141443 > : Serializing Heartbeat messages from =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 4.749, =20 > num_per_second: 21057.1 > times-debug-modified.txt : num: 100000, seconds: 2.671, =20 > num_per_second: 37439.2 > times-optimized-normal.txt : num: 100000, seconds: 3.053, =20 > num_per_second: 32754.7 > times-optimized-modified.txt: num: 100000, seconds: 1.782, =20 > num_per_second: 56116.7 > : Creating NewOrderSingle messages: > times-debug-normal.txt : num: 100000, seconds: 6.422, =20 > num_per_second: 15571.5 > times-debug-modified.txt : num: 100000, seconds: 3.937, =20 > num_per_second: 25400.1 > times-optimized-normal.txt : num: 100000, seconds: 4.778, =20 > num_per_second: 20929.3 > times-optimized-modified.txt: num: 100000, seconds: 3.026, =20 > num_per_second: 33046.9 > : Serializing NewOrderSingle messages to =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 6.429, =20 > num_per_second: 15554.5 > times-debug-modified.txt : num: 100000, seconds: 3.84, =20 > num_per_second: 26041.7 > times-optimized-normal.txt : num: 100000, seconds: 4.874, =20 > num_per_second: 20517 > times-optimized-modified.txt: num: 100000, seconds: 3.029, =20 > num_per_second: 33014.2 > : Serializing NewOrderSingle messages from = > strings: > times-debug-normal.txt : num: 100000, seconds: 9.608, =20 > num_per_second: 10408 > times-debug-modified.txt : num: 100000, seconds: 5.385, =20 > num_per_second: 18570.1 > times-optimized-normal.txt : num: 100000, seconds: 7.202, =20 > num_per_second: 13885 > times-optimized-modified.txt: num: 100000, seconds: 3.779, =20 > num_per_second: 26462 > : Creating QuoteRequest messages: > times-debug-normal.txt : num: 100000, seconds: 93.295, =20 > num_per_second: 1071.87 > times-debug-modified.txt : num: 100000, seconds: 46.975, =20 > num_per_second: 2128.79 > times-optimized-normal.txt : num: 100000, seconds: 61.148, =20 > num_per_second: 1635.38 > times-optimized-modified.txt: num: 100000, seconds: 33.904, =20 > num_per_second: 2949.5 > : Serializing QuoteRequest messages to =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 11.052, =20 > num_per_second: 9048.14 > times-debug-modified.txt : num: 100000, seconds: 10.691, =20 > num_per_second: 9353.66 > times-optimized-normal.txt : num: 100000, seconds: 5.667, =20 > num_per_second: 17646 > times-optimized-modified.txt: num: 100000, seconds: 4.808, =20 > num_per_second: 20798.7 > : Serializing QuoteRequest messages from =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 74.91, =20 > num_per_second: 1334.94 > times-debug-modified.txt : num: 100000, seconds: 48.556, =20 > num_per_second: 2059.48 > times-optimized-normal.txt : num: 100000, seconds: 47.944, =20 > num_per_second: 2085.77 > times-optimized-modified.txt: num: 100000, seconds: 28.627, =20 > num_per_second: 3493.21 > : Reading fields from QuoteRequest message: > times-debug-normal.txt : num: 100000, seconds: 34.526, =20 > num_per_second: 2896.37 > times-debug-modified.txt : num: 100000, seconds: 12.988, =20 > num_per_second: 7699.41 > times-optimized-normal.txt : num: 100000, seconds: 21.891, =20 > num_per_second: 4568.09 > times-optimized-modified.txt: num: 100000, seconds: 6.875, =20 > num_per_second: 14545.5 > : Storing NewOrderSingle messages: > times-debug-normal.txt : num: 100000, seconds: 0.765, =20 > num_per_second: 130719 > times-debug-modified.txt : num: 100000, seconds: 0.71, =20 > num_per_second: 140845 > times-optimized-normal.txt : num: 100000, seconds: 0.575, =20 > num_per_second: 173913 > times-optimized-modified.txt: num: 100000, seconds: 0.521, =20 > num_per_second: 191939 > : Validating NewOrderSingle messages with =20 > no data dictionary: > times-debug-normal.txt : num: 100000, seconds: 1.489, =20 > num_per_second: 67159.2 > times-debug-modified.txt : num: 100000, seconds: 0.859, =20 > num_per_second: 116414 > times-optimized-normal.txt : num: 100000, seconds: 0.843, =20 > num_per_second: 118624 > times-optimized-modified.txt: num: 100000, seconds: 0.426, =20 > num_per_second: 234742 > : Validating NewOrderSingle messages with =20 > data dictionary: > times-debug-normal.txt : num: 100000, seconds: 7.732, =20 > num_per_second: 12933.3 > times-debug-modified.txt : num: 100000, seconds: 6.105, =20 > num_per_second: 16380 > times-optimized-normal.txt : num: 100000, seconds: 2.485, =20 > num_per_second: 40241.4 > times-optimized-modified.txt: num: 100000, seconds: 1.717, =20 > num_per_second: 58241.1 > > > --- quickfix/src/C++/FieldConvertors.h 2004-04-29 20:58:20.000000000 =20 > +0100 > +++ quickfix-debug-modified/src/C++/FieldConvertors.h 2004-08-12 =20 > 19:13:22.036829060 +0100 > @@ -1,3 +1,4 @@ > + > /* -*- C++ -*- */ > > =20 > /=20 > ***********************************************************************= > ***** > @@ -32,6 +33,76 @@ > > namespace FIX > { > +template<class T> > +static inline char * integer_to_string (char * buf, const size_t len, = > T t) > +{ > + const bool is_neg =3D t < 0; > + char * p =3D buf + len; > + > + *--p =3D '\0'; > + > + if (is_neg) { > + if (t =3D=3D std::numeric_limits<T>::min()) { > + *--p =3D '0' + (10-t%10)%10; > + t/=3D10; > + } > + t=3D-t; > + do { > + *--p =3D '0' + t % 10; > + t /=3D 10; > + } while (t > 0); > + *--p =3D '-'; > + } else { > + do { > + *--p =3D '0' + t % 10; > + t /=3D 10; > + } while (t > 0); > + } > + return p; > +} > + > + > + > +template<class T> > +static inline char * integer_to_string_padded (char * buf, > + const size_t len, > + T t, > + const size_t width =3D 0, > + const char padding_char =3D '0') > +{ > + if (!width) return integer_to_string (buf, len, t); > + > + const bool is_neg =3D t < 0; > + char * p =3D buf + len; > + > + *--p =3D '\0'; > + > + if (is_neg) { > + if (t =3D=3D std::numeric_limits<T>::min()) { > + *--p =3D '0' + (10-t%10)%10; > + t/=3D10; > + } > + t=3D-t; > + do { > + *--p =3D '0' + t % 10; > + t /=3D 10; > + } while (t > 0); > + if (p > buf) > + *--p =3D '-'; > + } else { > + do { > + *--p =3D '0' + t % 10; > + t /=3D 10; > + } while (t > 0); > + } > + const char * stop_p =3D buf + len - width - 1; > + if (stop_p < buf) stop_p =3D buf; > + while (p > stop_p) > + *--p =3D padding_char; > + return p; > +} > + > + > /// Empty convertor is a no-op. > struct EmptyConvertor > { > @@ -46,21 +117,32 @@ > { > static std::string convert( long value ) > { > - char temp[ 12 ]; > - memset( temp, 0, 12 * sizeof( char ) ); > - sprintf( temp, "%d", ( int ) value ); > - return temp; > + // buffer is big enough for significant digits and extra digit, =20 > minus and null > + char buffer [std::numeric_limits<long>::digits10 + 3]; > + const char * const start =3D integer_to_string (buffer, sizeof =20 > (buffer), value); > + return std::string (start, buffer + sizeof (buffer) - start - 1); > } > > static bool convert( const std::string& value, long& result ) > { > const char * str =3D value.c_str(); > - if ( *str =3D=3D '-' ) ++str; > - for ( const char * p =3D str; *p !=3D 0; ++p ) > - { > - if ( !isdigit( *p ) ) return false; > + bool is_neg =3D false; > + long x =3D 0; > + > + if (*str =3D=3D '-') { > + is_neg =3D true; > + ++str; > } > - result =3D atol( value.c_str() ); > + > + do { > + const int c =3D *str - '0'; > + if (c < 0 || 9 < c) return false; > + x =3D 10 * x + c; > + } while (*++str); > + > + if (is_neg) x =3D -x; > + > + result =3D x; > return true; > } > > @@ -81,9 +163,10 @@ > throw( FieldConvertError& ) > { > if ( value > 255 || value < 0 ) throw FieldConvertError(); > - std::stringstream stream; > - stream << std::setw( 3 ) << std::setfill( '0' ) << value; > - return stream.str(); > + char result [4]; > + if (integer_to_string_padded (result, sizeof(result), value, 3, =20 > '0') !=3D result) > + throw FieldConvertError(); > + return std::string (result, 3); > } > > static bool convert( const std::string& value, long& result ) > @@ -104,53 +187,32 @@ > static std::string convert( double value ) > { > char result[ 32 ]; > - memset( result, 0, 32 * sizeof( char ) ); > - sprintf( result, "%.15g", value ); > - return result; > + return std::string (result, std::sprintf( result, "%.15g", value =20 > )); > } > > static bool convert( const std::string& value, double& result ) > { > - if ( !value.size() ) return false; > - if ( value =3D=3D "." ) return false; > - > - result =3D atof( const_cast < char* > ( value.c_str() ) ); > - std::string stripped =3D value; > - > - // add leading zero if none exists > - if ( *stripped.begin() =3D=3D '.' ) > - stripped =3D '0' + stripped; > - > - // remove extra leading zeros > - while ( stripped.size() > 1 > - && *(stripped.begin()) =3D=3D '0' > - && isdigit(*(stripped.begin()+1)) ) > - { > - stripped.erase( stripped.begin() ); > + const char * i =3D value.c_str(); > + > + if (!*i) return false; // Catch null =20 > strings > + if (*i =3D=3D '-' && !*++i) return false; // Eat leadin= g =20 > '-' and recheck for null string > + > + bool have_digit =3D false; > + > + if (std::isdigit (*i)) { > + have_digit =3D true; > + while (std::isdigit (*++i)); > } > > - if ( stripped.find( '.' ) !=3D std::string::npos ) > - { > - std::string::reverse_iterator r =3D stripped.rbegin(); > - while ( r !=3D stripped.rend() && ( *r =3D=3D '0' || *r =3D=3D '.'= ) ) > - { > - if ( *r =3D=3D '.' ) { stripped.resize( stripped.size() - 1 ); = > break; } > - stripped.resize( stripped.size() - 1 ); r++; > - } > - } > - if ( *stripped.begin() =3D=3D '0' ) > - { > - std::string::size_type i =3D stripped.find_first_not_of( '0' ); > - std::string::size_type dot =3D stripped.find( '.' ); > - if ( i !=3D dot ) > - stripped =3D stripped.substr( i ); > + if (*i =3D=3D '.' && std::isdigit (*++i)) { > + have_digit =3D true; > + while (std::isdigit (*++i)); > } > > - std::string converted =3D convert( result ); > - if ( stripped.size() !=3D converted.size() ) return false; > + if (*i || !have_digit) return false; > > - // strcmp is being used because =3D=3D operator is funky under linux > - return ( strcmp( stripped.c_str(), converted.c_str() ) =3D=3D 0 ); > + result =3D std::strtod (value.c_str(), 0); > + return true; > } > > static double convert( const std::string& value ) > @@ -169,16 +231,13 @@ > { > static std::string convert( char value ) > { > - char temp[ 2 ]; > - temp[ 0 ] =3D value; > - temp[ 1 ] =3D '\0'; > - return temp; > + return std::string (1, value); > } > > static bool convert( const std::string& value, char& result ) > { > - if ( value.size() =3D=3D 0 ) return false; > - result =3D *value.c_str(); > + if ( value.size() !=3D 1 ) return false; > + result =3D value[0]; > return true; > } > > @@ -197,15 +256,19 @@ > struct BoolConvertor > { > static std::string convert( bool value ) > - { return value ? "Y" : "N"; } > + { > + const char ch =3D value ? 'Y' : 'N'; > + return std::string (1, ch); > + } > > static bool convert( const std::string& value, bool& result ) > { > - if ( value =3D=3D "Y" ) result =3D true; > - else > - if ( value =3D=3D "N" ) result =3D false; > - else > - return false; > + if (value.size() !=3D 1) return false; > + switch (value[0]) { > + case 'Y': result =3D true; break; > + case 'N': result =3D false; break; > + default: return false; > + } > return true; > } > > @@ -227,13 +290,19 @@ > throw( FieldConvertError& ) > { > char result[ 18+4 ]; > - int len =3D strftime( result, 18, "%Y%m%d-%H:%M:%S", value ); > - if ( len !=3D 17 ) throw FieldConvertError(); > + > + integer_to_string_padded (result , 5, static_cast<const =20 > tm*>(value)->tm_year + 1900, 4, '0'); > + integer_to_string_padded (result + 4, 3, static_cast<const =20 > tm*>(value)->tm_mon + 1, 2, '0'); > + integer_to_string_padded (result + 6, 3, static_cast<const =20 > tm*>(value)->tm_mday, 2, '0'); result[8] =3D '-'; > + integer_to_string_padded (result + 9, 3, static_cast<const =20 > tm*>(value)->tm_hour, 2, '0'); result[11] =3D ':'; > + integer_to_string_padded (result + 12, 3, static_cast<const =20 > tm*>(value)->tm_min, 2, '0'); result[14] =3D ':'; > + integer_to_string_padded (result + 15, 3, static_cast<const =20 > tm*>(value)->tm_sec, 2, '0'); > > if(true=3D=3DshowMilliseconds) > { > - len =3D sprintf(result+17,".%03d",value.getMillisecond()); > - if ( len !=3D 4) throw FieldConvertError(); > + result[17] =3D '.'; > + if (integer_to_string_padded (result + 18, 4, =20 > value.getMillisecond(), 3, '0') !=3D result + 18) > + throw FieldConvertError(); > } > return result; > } > @@ -242,19 +311,73 @@ > throw( FieldConvertError& ) > { > UtcTimeStamp result; > - const char* val =3D value.c_str(); > - const char* len =3D strptime( val, "%Y%m%d-%H:%M:%S", result ); > - if ( len - val !=3D 17 ) throw FieldConvertError(); > - > - // if we have milliseconds in the string, *len should be ".sss" > - result.setMillisecond(0); > - if(NULL !=3D len && strlen(len)=3D=3D4 && len[0] =3D=3D '.') > - { > - int ms =3D atoi(&len[1]); > - if(ms < 0 || ms > 999) throw FieldConvertError(); > - result.setMillisecond(ms); > + bool have_milliseconds =3D false; > + > + switch (value.size()) { > + case 21: have_milliseconds =3D true; > + case 17: break; > + default: throw FieldConvertError(); > } > > + int i =3D 0; > + for (int c=3D0; c<8; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D '-') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D ':') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D ':') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (have_milliseconds) { > + if (value[i++] !=3D '.') throw FieldConvertError(); > + for (int c=3D0; c<3; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + } > + > + tm & result_tm =3D *static_cast<tm*>(result); > + > + i =3D 0; > + > + result_tm.tm_year =3D value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year -=3D 1900; > + > + result_tm.tm_mon =3D value[i++] - '0'; > + result_tm.tm_mon =3D 10 * result_tm.tm_mon + value[i++] - '0'; > + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw =20 > FieldConvertError(); > + --result_tm.tm_mon; > + > + result_tm.tm_mday =3D value[i++] - '0'; > + result_tm.tm_mday =3D 10 * result_tm.tm_mday + value[i++] - '0'; > + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw =20 > FieldConvertError(); > + > + ++i; // skip '-' > + > + result_tm.tm_hour =3D value[i++] - '0'; > + result_tm.tm_hour =3D 10 * result_tm.tm_hour + value[i++] - '0'; > + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No =20 > check for >=3D 0 as no '-' are converted here > + > + ++i; // skip ':' > + > + result_tm.tm_min =3D value[i++] - '0'; > + result_tm.tm_min =3D 10 * result_tm.tm_min + value[i++] - '0'; > + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check = > for >=3D 0 as no '-' are converted here > + > + ++i; // skip ':' > + > + result_tm.tm_sec =3D value[i++] - '0'; > + result_tm.tm_sec =3D 10 * result_tm.tm_sec + value[i++] - '0'; > + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check = > for >=3D 0 as no '-' are converted here > + > + if (have_milliseconds) > + result.setMillisecond (100 * (value[i+1] - '0') + > + 10 * (value[i+2] - '0') + > + (value[i+3] - '0')); > + else > + result.setMillisecond (0); > + > + result_tm.tm_isdst =3D -1; > + > return result; > } > }; > @@ -266,13 +389,16 @@ > throw( FieldConvertError& ) > { > char result[ 9+4 ]; > - int len =3D strftime( result, 9, "%H:%M:%S", value ); > - if ( len !=3D 8 ) throw FieldConvertError(); > + > + integer_to_string_padded (result , 3, static_cast<const =20 > tm*>(value)->tm_hour, 2, '0'); result[2] =3D ':'; > + integer_to_string_padded (result + 3, 3, static_cast<const =20 > tm*>(value)->tm_min, 2, '0'); result[5] =3D ':'; > + integer_to_string_padded (result + 6, 3, static_cast<const =20 > tm*>(value)->tm_sec, 2, '0'); > > if(true=3D=3DshowMilliseconds) > { > - len =3D sprintf(result+8,".%03d",value.getMillisecond()); > - if ( len !=3D 4) throw FieldConvertError(); > + result[8] =3D '.'; > + if (integer_to_string_padded (result + 9, 4, =20 > value.getMillisecond(), 3, '0') !=3D result + 9) > + throw FieldConvertError(); > } > > return result; > @@ -282,19 +408,52 @@ > throw( FieldConvertError& ) > { > UtcTimeOnly result; > - const char* val =3D value.c_str(); > - const char* len =3D strptime( val, "%H:%M:%S", result ); > - if ( len - val !=3D 8 ) throw FieldConvertError(); > - > - // if we have milliseconds in the string, *len should be ".sss" > - result.setMillisecond(0); > - if(NULL !=3D len && strlen(len)=3D=3D4 && len[0] =3D=3D '.') > - { > - int ms =3D atoi(&len[1]); > - if(ms < 0 || ms > 999) throw FieldConvertError(); > - result.setMillisecond(ms); > + bool have_milliseconds =3D false; > + > + switch (value.size()) { > + case 12: have_milliseconds =3D true; > + case 8: break; > + default: throw FieldConvertError(); > + } > + > + int i =3D 0; > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D ':') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D ':') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (have_milliseconds) { > + // ++i instead of i++ skips the '.' separator > + for (int c=3D0; c<3; ++c) if (!std::isdigit(value[++i])) throw =20 > FieldConvertError(); > } > > + tm & result_tm =3D *static_cast<tm*>(result); > + > + i =3D 0; > + > + result_tm.tm_hour =3D value[i++] - '0'; > + result_tm.tm_hour =3D 10 * result_tm.tm_hour + value[i++] - '0'; > + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No =20 > check for >=3D 0 as no '-' are converted here > + ++i; // skip ':' > + > + result_tm.tm_min =3D value[i++] - '0'; > + result_tm.tm_min =3D 10 * result_tm.tm_min + value[i++] - '0'; > + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check = > for >=3D 0 as no '-' are converted here > + ++i; // skip ':' > + > + result_tm.tm_sec =3D value[i++] - '0'; > + result_tm.tm_sec =3D 10 * result_tm.tm_sec + value[i++] - '0'; > + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check = > for >=3D 0 as no '-' are converted here > + > + if (have_milliseconds) > + result.setMillisecond (100 * (value[i+1] - '0') + > + 10 * (value[i+2] - '0') + > + (value[i+3] - '0')); > + else > + result.setMillisecond (0); > + > + result_tm.tm_isdst =3D -1; > + > return result; > } > }; > @@ -306,8 +465,9 @@ > throw( FieldConvertError& ) > { > char result[ 9 ]; > - int len =3D strftime( result, 9, "%Y%m%d", value ); > - if ( len !=3D 8 ) throw FieldConvertError(); > + integer_to_string_padded (result , 5, static_cast<const =20 > tm*>(value)->tm_year + 1900, 4, '0'); > + integer_to_string_padded (result + 4, 3, static_cast<const =20 > tm*>(value)->tm_mon + 1, 2, '0'); > + integer_to_string_padded (result + 6, 3, static_cast<const =20 > tm*>(value)->tm_mday, 2, '0'); > return result; > } > > @@ -315,9 +475,34 @@ > throw( FieldConvertError& ) > { > UtcDate result; > - const char* val =3D value.c_str(); > - const char* len =3D strptime( val, "%Y%m%d", result ); > - if ( len - val !=3D 8 ) throw FieldConvertError(); > + > + if (value.size() !=3D 8) throw FieldConvertError(); > + > + int i =3D 0; > + for (int c=3D0; c<8; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + > + tm & result_tm =3D *static_cast<tm*>(result); > + > + i =3D 0; > + > + result_tm.tm_year =3D value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year -=3D 1900; > + > + result_tm.tm_mon =3D value[i++] - '0'; > + result_tm.tm_mon =3D 10 * result_tm.tm_mon + value[i++] - '0'; > + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw =20 > FieldConvertError(); > + --result_tm.tm_mon; > + > + result_tm.tm_mday =3D value[i++] - '0'; > + result_tm.tm_mday =3D 10 * result_tm.tm_mday + value[i++] - '0'; > + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw =20 > FieldConvertError(); > + ++i; // skip '-' > + > + result_tm.tm_isdst =3D -1; > + > return result; > } > }; > > > <font face=3D"Times New Roman" size=3D"3"> > <p>--------------------------------------------------------------------= > ----------</p> > <p> This email is intended only for the use of the individual(s) to =20 > whom it is addressed and may be privileged and confidential. =20 > Unauthorised use or disclosure is prohibited. If you receive this =20 > e-mail in error, please advise immediately and delete the original =20 > message. This message may have been altered without your or our =20 > knowledge and the sender does not accept any liability for any errors =20 > or omissions in the message.</p> > <p>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D</p> > </font> > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > <font face=3D"Times New Roman" size=3D"3"> <p>------------------------------------------------------------------------= ------</p> <p> This email is intended only for the use of the individual(s) to whom it= is addressed and may be privileged and confidential. Unauthorised use or d= isclosure is prohibited. If you receive this e-mail in error, please advise= immediately and delete the original message. This message may have been al= tered without your or our knowledge and the sender does not accept any liab= ility for any errors or omissions in the message.</p> <p>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D</p> </font> |
From: Peterson, K. <kri...@rb...> - 2004-08-16 10:02:17
|
Oren - I've replaced atol() and printf() for the string->long and long->string con= versions with inlined, handwritten routines that are 4x-8x faster. For doub= le->string, I've removed the unnecessary memset() which is why speed up is = only 3x. With string->double conversions, prior code was effectively conver= ting string to double, then converting the double back to a string and then= comparing the strings, before using strtod() to convert the string to a do= uble. I replaced this with code that effectively checks the string against = the regex ^-?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)$ and then uses strtod() to do = the conversion, resulting in a 12x-18x speedup. I've tested these changes on Linux/AthlonXP and Solaris/SPARC and have seen= substantial performance improvements in both, and can not explain why you = aren't seeing the full effect. The only thing that comes to mind is that pe= rhaps 'pt' is being linked against a libquickfix.a build with the old Field= Convertors.h. As the methods are inlined, it is not enough to rebuild pt an= d libquickfixcpptest.a; libquickfix.a must be recompiled as well. - Kris -----Original Message----- From: Oren Miller [mailto:or...@qu...] Sent: 13 August 2004 16:52 To: Peterson, Kristofer Cc: QuickFIX Development (E-mail) Subject: Re: [Quickfix-developers] FieldConvertor.h optimizations Thanks Kristopher, I ran these through and was able to see nice performance improvements =20 on serializing to strings, however for some reasons the performance for =20 serializing from strings remained unchanged on the systems I tested =20 under. Also converting from doubles to strings showed no improvement. =20 I tried this under a i686 Xeon and a powerpc chipsets. --oren On Aug 12, 2004, at 2:13 PM, Peterson, Kristofer wrote: > QuickFIX Documentation: =20 > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: =20 > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > I have optimized some of the field convertors in FieldConvertors.h and = > have achieved substantial improvements in performance (generally 50% - = > 200% faster). I include a patch against the FieldConvertors.h file =20 > from quickfix-1.7.1. > > The code is admittedly 'C-ish', however no interface has been changed =20 > and I believe the results speak for themselves. > > Replacing strtod() in the double to string conversion would probably =20 > be a significant win, although I don't know of any efficient =20 > algorithms for this conversion. > > Finally, time stamp conversions should probably be added to pt as well. > > Cheers, > > - Kris > > The times were obtained from pt running on an AthlonXP 2500 running =20 > Linux kernel 2.6.7 compiled with g++ 3.3.4. 'normal' builds used the =20 > existing FieldConvertors.h, 'modified' builds used the modified =20 > FieldConvertors.h. > > Optimization flags for the builds were as follows: > > quickfix-debug-modified/Makefile:CFLAGS =3D -g -Wall > quickfix-debug-normal/Makefile:CFLAGS =3D -g -Wall > quickfix-optimized-modified/Makefile:CFLAGS =3D -g -O3 -ffast-math =20 > -mcpu=3Dathlon-xp -Wall > quickfix-optimized-normal/Makefile:CFLAGS =3D -g -O3 -ffast-math =20 > -mcpu=3Dathlon-xp -Wall > > times-debug-normal.txt : peterson@karl src $ ./pt -c 100000 > times-debug-modified.txt : peterson@karl src $ ./pt -c 100000 > times-optimized-normal.txt : peterson@karl src $ ./pt -c 100000 > times-optimized-modified.txt: peterson@karl src $ ./pt -c 100000 > > : Converting integers to strings: > times-debug-normal.txt : num: 100000, seconds: 0.259, =20 > num_per_second: 386100 > times-debug-modified.txt : num: 100000, seconds: 0.032, =20 > num_per_second: 3.125e+06 > times-optimized-normal.txt : num: 100000, seconds: 0.183, =20 > num_per_second: 546448 > times-optimized-modified.txt: num: 100000, seconds: 0.026, =20 > num_per_second: 3.84615e+06 > : Converting strings to integers: > times-debug-normal.txt : num: 100000, seconds: 0.024, =20 > num_per_second: 4.16667e+06 > times-debug-modified.txt : num: 100000, seconds: 0.008, =20 > num_per_second: 1.25e+07 > times-optimized-normal.txt : num: 100000, seconds: 0.016, =20 > num_per_second: 6.25e+06 > times-optimized-modified.txt: num: 100000, seconds: 0.004, =20 > num_per_second: 2.5e+07 > : Converting doubles to strings: > times-debug-normal.txt : num: 100000, seconds: 0.711, =20 > num_per_second: 140647 > times-debug-modified.txt : num: 100000, seconds: 0.243, =20 > num_per_second: 411523 > times-optimized-normal.txt : num: 100000, seconds: 0.531, =20 > num_per_second: 188324 > times-optimized-modified.txt: num: 100000, seconds: 0.236, =20 > num_per_second: 423729 > : Converting strings to doubles: > times-debug-normal.txt : num: 100000, seconds: 0.987, =20 > num_per_second: 101317 > times-debug-modified.txt : num: 100000, seconds: 0.058, =20 > num_per_second: 1.72414e+06 > times-optimized-normal.txt : num: 100000, seconds: 0.725, =20 > num_per_second: 137931 > times-optimized-modified.txt: num: 100000, seconds: 0.062, =20 > num_per_second: 1.6129e+06 > : Creating Heartbeat messages: > times-debug-normal.txt : num: 100000, seconds: 1.823, =20 > num_per_second: 54854.6 > times-debug-modified.txt : num: 100000, seconds: 1.166, =20 > num_per_second: 85763.3 > times-optimized-normal.txt : num: 100000, seconds: 1.242, =20 > num_per_second: 80515.3 > times-optimized-modified.txt: num: 100000, seconds: 0.825, =20 > num_per_second: 121212 > : Serializing Heartbeat messages to =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 2.35, =20 > num_per_second: 42553.2 > times-debug-modified.txt : num: 100000, seconds: 1.198, =20 > num_per_second: 83472.5 > times-optimized-normal.txt : num: 100000, seconds: 1.425, =20 > num_per_second: 70175.4 > times-optimized-modified.txt: num: 100000, seconds: 0.707, =20 > num_per_second: 141443 > : Serializing Heartbeat messages from =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 4.749, =20 > num_per_second: 21057.1 > times-debug-modified.txt : num: 100000, seconds: 2.671, =20 > num_per_second: 37439.2 > times-optimized-normal.txt : num: 100000, seconds: 3.053, =20 > num_per_second: 32754.7 > times-optimized-modified.txt: num: 100000, seconds: 1.782, =20 > num_per_second: 56116.7 > : Creating NewOrderSingle messages: > times-debug-normal.txt : num: 100000, seconds: 6.422, =20 > num_per_second: 15571.5 > times-debug-modified.txt : num: 100000, seconds: 3.937, =20 > num_per_second: 25400.1 > times-optimized-normal.txt : num: 100000, seconds: 4.778, =20 > num_per_second: 20929.3 > times-optimized-modified.txt: num: 100000, seconds: 3.026, =20 > num_per_second: 33046.9 > : Serializing NewOrderSingle messages to =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 6.429, =20 > num_per_second: 15554.5 > times-debug-modified.txt : num: 100000, seconds: 3.84, =20 > num_per_second: 26041.7 > times-optimized-normal.txt : num: 100000, seconds: 4.874, =20 > num_per_second: 20517 > times-optimized-modified.txt: num: 100000, seconds: 3.029, =20 > num_per_second: 33014.2 > : Serializing NewOrderSingle messages from = > strings: > times-debug-normal.txt : num: 100000, seconds: 9.608, =20 > num_per_second: 10408 > times-debug-modified.txt : num: 100000, seconds: 5.385, =20 > num_per_second: 18570.1 > times-optimized-normal.txt : num: 100000, seconds: 7.202, =20 > num_per_second: 13885 > times-optimized-modified.txt: num: 100000, seconds: 3.779, =20 > num_per_second: 26462 > : Creating QuoteRequest messages: > times-debug-normal.txt : num: 100000, seconds: 93.295, =20 > num_per_second: 1071.87 > times-debug-modified.txt : num: 100000, seconds: 46.975, =20 > num_per_second: 2128.79 > times-optimized-normal.txt : num: 100000, seconds: 61.148, =20 > num_per_second: 1635.38 > times-optimized-modified.txt: num: 100000, seconds: 33.904, =20 > num_per_second: 2949.5 > : Serializing QuoteRequest messages to =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 11.052, =20 > num_per_second: 9048.14 > times-debug-modified.txt : num: 100000, seconds: 10.691, =20 > num_per_second: 9353.66 > times-optimized-normal.txt : num: 100000, seconds: 5.667, =20 > num_per_second: 17646 > times-optimized-modified.txt: num: 100000, seconds: 4.808, =20 > num_per_second: 20798.7 > : Serializing QuoteRequest messages from =20 > strings: > times-debug-normal.txt : num: 100000, seconds: 74.91, =20 > num_per_second: 1334.94 > times-debug-modified.txt : num: 100000, seconds: 48.556, =20 > num_per_second: 2059.48 > times-optimized-normal.txt : num: 100000, seconds: 47.944, =20 > num_per_second: 2085.77 > times-optimized-modified.txt: num: 100000, seconds: 28.627, =20 > num_per_second: 3493.21 > : Reading fields from QuoteRequest message: > times-debug-normal.txt : num: 100000, seconds: 34.526, =20 > num_per_second: 2896.37 > times-debug-modified.txt : num: 100000, seconds: 12.988, =20 > num_per_second: 7699.41 > times-optimized-normal.txt : num: 100000, seconds: 21.891, =20 > num_per_second: 4568.09 > times-optimized-modified.txt: num: 100000, seconds: 6.875, =20 > num_per_second: 14545.5 > : Storing NewOrderSingle messages: > times-debug-normal.txt : num: 100000, seconds: 0.765, =20 > num_per_second: 130719 > times-debug-modified.txt : num: 100000, seconds: 0.71, =20 > num_per_second: 140845 > times-optimized-normal.txt : num: 100000, seconds: 0.575, =20 > num_per_second: 173913 > times-optimized-modified.txt: num: 100000, seconds: 0.521, =20 > num_per_second: 191939 > : Validating NewOrderSingle messages with =20 > no data dictionary: > times-debug-normal.txt : num: 100000, seconds: 1.489, =20 > num_per_second: 67159.2 > times-debug-modified.txt : num: 100000, seconds: 0.859, =20 > num_per_second: 116414 > times-optimized-normal.txt : num: 100000, seconds: 0.843, =20 > num_per_second: 118624 > times-optimized-modified.txt: num: 100000, seconds: 0.426, =20 > num_per_second: 234742 > : Validating NewOrderSingle messages with =20 > data dictionary: > times-debug-normal.txt : num: 100000, seconds: 7.732, =20 > num_per_second: 12933.3 > times-debug-modified.txt : num: 100000, seconds: 6.105, =20 > num_per_second: 16380 > times-optimized-normal.txt : num: 100000, seconds: 2.485, =20 > num_per_second: 40241.4 > times-optimized-modified.txt: num: 100000, seconds: 1.717, =20 > num_per_second: 58241.1 > > > --- quickfix/src/C++/FieldConvertors.h 2004-04-29 20:58:20.000000000 =20 > +0100 > +++ quickfix-debug-modified/src/C++/FieldConvertors.h 2004-08-12 =20 > 19:13:22.036829060 +0100 > @@ -1,3 +1,4 @@ > + > /* -*- C++ -*- */ > > =20 > /=20 > ***********************************************************************= > ***** > @@ -32,6 +33,76 @@ > > namespace FIX > { > +template<class T> > +static inline char * integer_to_string (char * buf, const size_t len, = > T t) > +{ > + const bool is_neg =3D t < 0; > + char * p =3D buf + len; > + > + *--p =3D '\0'; > + > + if (is_neg) { > + if (t =3D=3D std::numeric_limits<T>::min()) { > + *--p =3D '0' + (10-t%10)%10; > + t/=3D10; > + } > + t=3D-t; > + do { > + *--p =3D '0' + t % 10; > + t /=3D 10; > + } while (t > 0); > + *--p =3D '-'; > + } else { > + do { > + *--p =3D '0' + t % 10; > + t /=3D 10; > + } while (t > 0); > + } > + return p; > +} > + > + > + > +template<class T> > +static inline char * integer_to_string_padded (char * buf, > + const size_t len, > + T t, > + const size_t width =3D 0, > + const char padding_char =3D '0') > +{ > + if (!width) return integer_to_string (buf, len, t); > + > + const bool is_neg =3D t < 0; > + char * p =3D buf + len; > + > + *--p =3D '\0'; > + > + if (is_neg) { > + if (t =3D=3D std::numeric_limits<T>::min()) { > + *--p =3D '0' + (10-t%10)%10; > + t/=3D10; > + } > + t=3D-t; > + do { > + *--p =3D '0' + t % 10; > + t /=3D 10; > + } while (t > 0); > + if (p > buf) > + *--p =3D '-'; > + } else { > + do { > + *--p =3D '0' + t % 10; > + t /=3D 10; > + } while (t > 0); > + } > + const char * stop_p =3D buf + len - width - 1; > + if (stop_p < buf) stop_p =3D buf; > + while (p > stop_p) > + *--p =3D padding_char; > + return p; > +} > + > + > /// Empty convertor is a no-op. > struct EmptyConvertor > { > @@ -46,21 +117,32 @@ > { > static std::string convert( long value ) > { > - char temp[ 12 ]; > - memset( temp, 0, 12 * sizeof( char ) ); > - sprintf( temp, "%d", ( int ) value ); > - return temp; > + // buffer is big enough for significant digits and extra digit, =20 > minus and null > + char buffer [std::numeric_limits<long>::digits10 + 3]; > + const char * const start =3D integer_to_string (buffer, sizeof =20 > (buffer), value); > + return std::string (start, buffer + sizeof (buffer) - start - 1); > } > > static bool convert( const std::string& value, long& result ) > { > const char * str =3D value.c_str(); > - if ( *str =3D=3D '-' ) ++str; > - for ( const char * p =3D str; *p !=3D 0; ++p ) > - { > - if ( !isdigit( *p ) ) return false; > + bool is_neg =3D false; > + long x =3D 0; > + > + if (*str =3D=3D '-') { > + is_neg =3D true; > + ++str; > } > - result =3D atol( value.c_str() ); > + > + do { > + const int c =3D *str - '0'; > + if (c < 0 || 9 < c) return false; > + x =3D 10 * x + c; > + } while (*++str); > + > + if (is_neg) x =3D -x; > + > + result =3D x; > return true; > } > > @@ -81,9 +163,10 @@ > throw( FieldConvertError& ) > { > if ( value > 255 || value < 0 ) throw FieldConvertError(); > - std::stringstream stream; > - stream << std::setw( 3 ) << std::setfill( '0' ) << value; > - return stream.str(); > + char result [4]; > + if (integer_to_string_padded (result, sizeof(result), value, 3, =20 > '0') !=3D result) > + throw FieldConvertError(); > + return std::string (result, 3); > } > > static bool convert( const std::string& value, long& result ) > @@ -104,53 +187,32 @@ > static std::string convert( double value ) > { > char result[ 32 ]; > - memset( result, 0, 32 * sizeof( char ) ); > - sprintf( result, "%.15g", value ); > - return result; > + return std::string (result, std::sprintf( result, "%.15g", value =20 > )); > } > > static bool convert( const std::string& value, double& result ) > { > - if ( !value.size() ) return false; > - if ( value =3D=3D "." ) return false; > - > - result =3D atof( const_cast < char* > ( value.c_str() ) ); > - std::string stripped =3D value; > - > - // add leading zero if none exists > - if ( *stripped.begin() =3D=3D '.' ) > - stripped =3D '0' + stripped; > - > - // remove extra leading zeros > - while ( stripped.size() > 1 > - && *(stripped.begin()) =3D=3D '0' > - && isdigit(*(stripped.begin()+1)) ) > - { > - stripped.erase( stripped.begin() ); > + const char * i =3D value.c_str(); > + > + if (!*i) return false; // Catch null =20 > strings > + if (*i =3D=3D '-' && !*++i) return false; // Eat leadin= g =20 > '-' and recheck for null string > + > + bool have_digit =3D false; > + > + if (std::isdigit (*i)) { > + have_digit =3D true; > + while (std::isdigit (*++i)); > } > > - if ( stripped.find( '.' ) !=3D std::string::npos ) > - { > - std::string::reverse_iterator r =3D stripped.rbegin(); > - while ( r !=3D stripped.rend() && ( *r =3D=3D '0' || *r =3D=3D '.'= ) ) > - { > - if ( *r =3D=3D '.' ) { stripped.resize( stripped.size() - 1 ); = > break; } > - stripped.resize( stripped.size() - 1 ); r++; > - } > - } > - if ( *stripped.begin() =3D=3D '0' ) > - { > - std::string::size_type i =3D stripped.find_first_not_of( '0' ); > - std::string::size_type dot =3D stripped.find( '.' ); > - if ( i !=3D dot ) > - stripped =3D stripped.substr( i ); > + if (*i =3D=3D '.' && std::isdigit (*++i)) { > + have_digit =3D true; > + while (std::isdigit (*++i)); > } > > - std::string converted =3D convert( result ); > - if ( stripped.size() !=3D converted.size() ) return false; > + if (*i || !have_digit) return false; > > - // strcmp is being used because =3D=3D operator is funky under linux > - return ( strcmp( stripped.c_str(), converted.c_str() ) =3D=3D 0 ); > + result =3D std::strtod (value.c_str(), 0); > + return true; > } > > static double convert( const std::string& value ) > @@ -169,16 +231,13 @@ > { > static std::string convert( char value ) > { > - char temp[ 2 ]; > - temp[ 0 ] =3D value; > - temp[ 1 ] =3D '\0'; > - return temp; > + return std::string (1, value); > } > > static bool convert( const std::string& value, char& result ) > { > - if ( value.size() =3D=3D 0 ) return false; > - result =3D *value.c_str(); > + if ( value.size() !=3D 1 ) return false; > + result =3D value[0]; > return true; > } > > @@ -197,15 +256,19 @@ > struct BoolConvertor > { > static std::string convert( bool value ) > - { return value ? "Y" : "N"; } > + { > + const char ch =3D value ? 'Y' : 'N'; > + return std::string (1, ch); > + } > > static bool convert( const std::string& value, bool& result ) > { > - if ( value =3D=3D "Y" ) result =3D true; > - else > - if ( value =3D=3D "N" ) result =3D false; > - else > - return false; > + if (value.size() !=3D 1) return false; > + switch (value[0]) { > + case 'Y': result =3D true; break; > + case 'N': result =3D false; break; > + default: return false; > + } > return true; > } > > @@ -227,13 +290,19 @@ > throw( FieldConvertError& ) > { > char result[ 18+4 ]; > - int len =3D strftime( result, 18, "%Y%m%d-%H:%M:%S", value ); > - if ( len !=3D 17 ) throw FieldConvertError(); > + > + integer_to_string_padded (result , 5, static_cast<const =20 > tm*>(value)->tm_year + 1900, 4, '0'); > + integer_to_string_padded (result + 4, 3, static_cast<const =20 > tm*>(value)->tm_mon + 1, 2, '0'); > + integer_to_string_padded (result + 6, 3, static_cast<const =20 > tm*>(value)->tm_mday, 2, '0'); result[8] =3D '-'; > + integer_to_string_padded (result + 9, 3, static_cast<const =20 > tm*>(value)->tm_hour, 2, '0'); result[11] =3D ':'; > + integer_to_string_padded (result + 12, 3, static_cast<const =20 > tm*>(value)->tm_min, 2, '0'); result[14] =3D ':'; > + integer_to_string_padded (result + 15, 3, static_cast<const =20 > tm*>(value)->tm_sec, 2, '0'); > > if(true=3D=3DshowMilliseconds) > { > - len =3D sprintf(result+17,".%03d",value.getMillisecond()); > - if ( len !=3D 4) throw FieldConvertError(); > + result[17] =3D '.'; > + if (integer_to_string_padded (result + 18, 4, =20 > value.getMillisecond(), 3, '0') !=3D result + 18) > + throw FieldConvertError(); > } > return result; > } > @@ -242,19 +311,73 @@ > throw( FieldConvertError& ) > { > UtcTimeStamp result; > - const char* val =3D value.c_str(); > - const char* len =3D strptime( val, "%Y%m%d-%H:%M:%S", result ); > - if ( len - val !=3D 17 ) throw FieldConvertError(); > - > - // if we have milliseconds in the string, *len should be ".sss" > - result.setMillisecond(0); > - if(NULL !=3D len && strlen(len)=3D=3D4 && len[0] =3D=3D '.') > - { > - int ms =3D atoi(&len[1]); > - if(ms < 0 || ms > 999) throw FieldConvertError(); > - result.setMillisecond(ms); > + bool have_milliseconds =3D false; > + > + switch (value.size()) { > + case 21: have_milliseconds =3D true; > + case 17: break; > + default: throw FieldConvertError(); > } > > + int i =3D 0; > + for (int c=3D0; c<8; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D '-') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D ':') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D ':') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (have_milliseconds) { > + if (value[i++] !=3D '.') throw FieldConvertError(); > + for (int c=3D0; c<3; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + } > + > + tm & result_tm =3D *static_cast<tm*>(result); > + > + i =3D 0; > + > + result_tm.tm_year =3D value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year -=3D 1900; > + > + result_tm.tm_mon =3D value[i++] - '0'; > + result_tm.tm_mon =3D 10 * result_tm.tm_mon + value[i++] - '0'; > + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw =20 > FieldConvertError(); > + --result_tm.tm_mon; > + > + result_tm.tm_mday =3D value[i++] - '0'; > + result_tm.tm_mday =3D 10 * result_tm.tm_mday + value[i++] - '0'; > + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw =20 > FieldConvertError(); > + > + ++i; // skip '-' > + > + result_tm.tm_hour =3D value[i++] - '0'; > + result_tm.tm_hour =3D 10 * result_tm.tm_hour + value[i++] - '0'; > + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No =20 > check for >=3D 0 as no '-' are converted here > + > + ++i; // skip ':' > + > + result_tm.tm_min =3D value[i++] - '0'; > + result_tm.tm_min =3D 10 * result_tm.tm_min + value[i++] - '0'; > + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check = > for >=3D 0 as no '-' are converted here > + > + ++i; // skip ':' > + > + result_tm.tm_sec =3D value[i++] - '0'; > + result_tm.tm_sec =3D 10 * result_tm.tm_sec + value[i++] - '0'; > + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check = > for >=3D 0 as no '-' are converted here > + > + if (have_milliseconds) > + result.setMillisecond (100 * (value[i+1] - '0') + > + 10 * (value[i+2] - '0') + > + (value[i+3] - '0')); > + else > + result.setMillisecond (0); > + > + result_tm.tm_isdst =3D -1; > + > return result; > } > }; > @@ -266,13 +389,16 @@ > throw( FieldConvertError& ) > { > char result[ 9+4 ]; > - int len =3D strftime( result, 9, "%H:%M:%S", value ); > - if ( len !=3D 8 ) throw FieldConvertError(); > + > + integer_to_string_padded (result , 3, static_cast<const =20 > tm*>(value)->tm_hour, 2, '0'); result[2] =3D ':'; > + integer_to_string_padded (result + 3, 3, static_cast<const =20 > tm*>(value)->tm_min, 2, '0'); result[5] =3D ':'; > + integer_to_string_padded (result + 6, 3, static_cast<const =20 > tm*>(value)->tm_sec, 2, '0'); > > if(true=3D=3DshowMilliseconds) > { > - len =3D sprintf(result+8,".%03d",value.getMillisecond()); > - if ( len !=3D 4) throw FieldConvertError(); > + result[8] =3D '.'; > + if (integer_to_string_padded (result + 9, 4, =20 > value.getMillisecond(), 3, '0') !=3D result + 9) > + throw FieldConvertError(); > } > > return result; > @@ -282,19 +408,52 @@ > throw( FieldConvertError& ) > { > UtcTimeOnly result; > - const char* val =3D value.c_str(); > - const char* len =3D strptime( val, "%H:%M:%S", result ); > - if ( len - val !=3D 8 ) throw FieldConvertError(); > - > - // if we have milliseconds in the string, *len should be ".sss" > - result.setMillisecond(0); > - if(NULL !=3D len && strlen(len)=3D=3D4 && len[0] =3D=3D '.') > - { > - int ms =3D atoi(&len[1]); > - if(ms < 0 || ms > 999) throw FieldConvertError(); > - result.setMillisecond(ms); > + bool have_milliseconds =3D false; > + > + switch (value.size()) { > + case 12: have_milliseconds =3D true; > + case 8: break; > + default: throw FieldConvertError(); > + } > + > + int i =3D 0; > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D ':') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (value[i++] !=3D ':') throw =20 > FieldConvertError(); > + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + if (have_milliseconds) { > + // ++i instead of i++ skips the '.' separator > + for (int c=3D0; c<3; ++c) if (!std::isdigit(value[++i])) throw =20 > FieldConvertError(); > } > > + tm & result_tm =3D *static_cast<tm*>(result); > + > + i =3D 0; > + > + result_tm.tm_hour =3D value[i++] - '0'; > + result_tm.tm_hour =3D 10 * result_tm.tm_hour + value[i++] - '0'; > + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No =20 > check for >=3D 0 as no '-' are converted here > + ++i; // skip ':' > + > + result_tm.tm_min =3D value[i++] - '0'; > + result_tm.tm_min =3D 10 * result_tm.tm_min + value[i++] - '0'; > + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check = > for >=3D 0 as no '-' are converted here > + ++i; // skip ':' > + > + result_tm.tm_sec =3D value[i++] - '0'; > + result_tm.tm_sec =3D 10 * result_tm.tm_sec + value[i++] - '0'; > + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check = > for >=3D 0 as no '-' are converted here > + > + if (have_milliseconds) > + result.setMillisecond (100 * (value[i+1] - '0') + > + 10 * (value[i+2] - '0') + > + (value[i+3] - '0')); > + else > + result.setMillisecond (0); > + > + result_tm.tm_isdst =3D -1; > + > return result; > } > }; > @@ -306,8 +465,9 @@ > throw( FieldConvertError& ) > { > char result[ 9 ]; > - int len =3D strftime( result, 9, "%Y%m%d", value ); > - if ( len !=3D 8 ) throw FieldConvertError(); > + integer_to_string_padded (result , 5, static_cast<const =20 > tm*>(value)->tm_year + 1900, 4, '0'); > + integer_to_string_padded (result + 4, 3, static_cast<const =20 > tm*>(value)->tm_mon + 1, 2, '0'); > + integer_to_string_padded (result + 6, 3, static_cast<const =20 > tm*>(value)->tm_mday, 2, '0'); > return result; > } > > @@ -315,9 +475,34 @@ > throw( FieldConvertError& ) > { > UtcDate result; > - const char* val =3D value.c_str(); > - const char* len =3D strptime( val, "%Y%m%d", result ); > - if ( len - val !=3D 8 ) throw FieldConvertError(); > + > + if (value.size() !=3D 8) throw FieldConvertError(); > + > + int i =3D 0; > + for (int c=3D0; c<8; ++c) if (!std::isdigit(value[i++])) throw =20 > FieldConvertError(); > + > + tm & result_tm =3D *static_cast<tm*>(result); > + > + i =3D 0; > + > + result_tm.tm_year =3D value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year -=3D 1900; > + > + result_tm.tm_mon =3D value[i++] - '0'; > + result_tm.tm_mon =3D 10 * result_tm.tm_mon + value[i++] - '0'; > + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw =20 > FieldConvertError(); > + --result_tm.tm_mon; > + > + result_tm.tm_mday =3D value[i++] - '0'; > + result_tm.tm_mday =3D 10 * result_tm.tm_mday + value[i++] - '0'; > + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw =20 > FieldConvertError(); > + ++i; // skip '-' > + > + result_tm.tm_isdst =3D -1; > + > return result; > } > }; > > > <font face=3D"Times New Roman" size=3D"3"> > <p>--------------------------------------------------------------------= > ----------</p> > <p> This email is intended only for the use of the individual(s) to =20 > whom it is addressed and may be privileged and confidential. =20 > Unauthorised use or disclosure is prohibited. If you receive this =20 > e-mail in error, please advise immediately and delete the original =20 > message. This message may have been altered without your or our =20 > knowledge and the sender does not accept any liability for any errors =20 > or omissions in the message.</p> > <p>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D</p> > </font> > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > <font face=3D"Times New Roman" size=3D"3"> <p>------------------------------------------------------------------------= ------</p> <p> This email is intended only for the use of the individual(s) to whom it= is addressed and may be privileged and confidential. Unauthorised use or d= isclosure is prohibited. If you receive this e-mail in error, please advise= immediately and delete the original message. This message may have been al= tered without your or our knowledge and the sender does not accept any liab= ility for any errors or omissions in the message.</p> <p>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D</p> </font> |
From: Emil V. <que...@ho...> - 2004-08-14 10:15:09
|
Hi All, I'm using a SocketInitiator and I am calling start(), then stop(), and noticed, that if I call start() again, the initiator won't start because the m_stop member var. is never reverted back to false. So I'm wondering is this by design and will it cause other problems if really restarted? (this is QuickFix 1.7.1, looks tha same in 1.8) Best regards, Emil _________________________________________________________________ Protect your PC - get McAfee.com VirusScan Online http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963 |
From: Oren M. <or...@qu...> - 2004-08-13 16:28:47
|
Very silly of me, I was looking at the wrong numbers. My results look similar to yours. I've checked in the changes. --oren On Aug 13, 2004, at 10:51 AM, Oren Miller wrote: > Thanks Kristopher, > > I ran these through and was able to see nice performance improvements > on serializing to strings, however for some reasons the performance > for serializing from strings remained unchanged on the systems I > tested under. Also converting from doubles to strings showed no > improvement. I tried this under a i686 Xeon and a powerpc chipsets. > > --oren > > On Aug 12, 2004, at 2:13 PM, Peterson, Kristofer wrote: > >> QuickFIX Documentation: >> http://www.quickfixengine.org/quickfix/doc/html/index.html >> QuickFIX FAQ: >> http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ >> QuickFIX Support: http://www.quickfixengine.org/services.html >> >> I have optimized some of the field convertors in FieldConvertors.h >> and have achieved substantial improvements in performance (generally >> 50% - 200% faster). I include a patch against the FieldConvertors.h >> file from quickfix-1.7.1. >> >> The code is admittedly 'C-ish', however no interface has been changed >> and I believe the results speak for themselves. >> >> Replacing strtod() in the double to string conversion would probably >> be a significant win, although I don't know of any efficient >> algorithms for this conversion. >> >> Finally, time stamp conversions should probably be added to pt as >> well. >> >> Cheers, >> >> - Kris >> >> The times were obtained from pt running on an AthlonXP 2500 running >> Linux kernel 2.6.7 compiled with g++ 3.3.4. 'normal' builds used the >> existing FieldConvertors.h, 'modified' builds used the modified >> FieldConvertors.h. >> >> Optimization flags for the builds were as follows: >> >> quickfix-debug-modified/Makefile:CFLAGS = -g -Wall >> quickfix-debug-normal/Makefile:CFLAGS = -g -Wall >> quickfix-optimized-modified/Makefile:CFLAGS = -g -O3 -ffast-math >> -mcpu=athlon-xp -Wall >> quickfix-optimized-normal/Makefile:CFLAGS = -g -O3 -ffast-math >> -mcpu=athlon-xp -Wall >> >> times-debug-normal.txt : peterson@karl src $ ./pt -c 100000 >> times-debug-modified.txt : peterson@karl src $ ./pt -c 100000 >> times-optimized-normal.txt : peterson@karl src $ ./pt -c 100000 >> times-optimized-modified.txt: peterson@karl src $ ./pt -c 100000 >> >> : Converting integers to strings: >> times-debug-normal.txt : num: 100000, seconds: 0.259, >> num_per_second: 386100 >> times-debug-modified.txt : num: 100000, seconds: 0.032, >> num_per_second: 3.125e+06 >> times-optimized-normal.txt : num: 100000, seconds: 0.183, >> num_per_second: 546448 >> times-optimized-modified.txt: num: 100000, seconds: 0.026, >> num_per_second: 3.84615e+06 >> : Converting strings to integers: >> times-debug-normal.txt : num: 100000, seconds: 0.024, >> num_per_second: 4.16667e+06 >> times-debug-modified.txt : num: 100000, seconds: 0.008, >> num_per_second: 1.25e+07 >> times-optimized-normal.txt : num: 100000, seconds: 0.016, >> num_per_second: 6.25e+06 >> times-optimized-modified.txt: num: 100000, seconds: 0.004, >> num_per_second: 2.5e+07 >> : Converting doubles to strings: >> times-debug-normal.txt : num: 100000, seconds: 0.711, >> num_per_second: 140647 >> times-debug-modified.txt : num: 100000, seconds: 0.243, >> num_per_second: 411523 >> times-optimized-normal.txt : num: 100000, seconds: 0.531, >> num_per_second: 188324 >> times-optimized-modified.txt: num: 100000, seconds: 0.236, >> num_per_second: 423729 >> : Converting strings to doubles: >> times-debug-normal.txt : num: 100000, seconds: 0.987, >> num_per_second: 101317 >> times-debug-modified.txt : num: 100000, seconds: 0.058, >> num_per_second: 1.72414e+06 >> times-optimized-normal.txt : num: 100000, seconds: 0.725, >> num_per_second: 137931 >> times-optimized-modified.txt: num: 100000, seconds: 0.062, >> num_per_second: 1.6129e+06 >> : Creating Heartbeat messages: >> times-debug-normal.txt : num: 100000, seconds: 1.823, >> num_per_second: 54854.6 >> times-debug-modified.txt : num: 100000, seconds: 1.166, >> num_per_second: 85763.3 >> times-optimized-normal.txt : num: 100000, seconds: 1.242, >> num_per_second: 80515.3 >> times-optimized-modified.txt: num: 100000, seconds: 0.825, >> num_per_second: 121212 >> : Serializing Heartbeat messages to >> strings: >> times-debug-normal.txt : num: 100000, seconds: 2.35, >> num_per_second: 42553.2 >> times-debug-modified.txt : num: 100000, seconds: 1.198, >> num_per_second: 83472.5 >> times-optimized-normal.txt : num: 100000, seconds: 1.425, >> num_per_second: 70175.4 >> times-optimized-modified.txt: num: 100000, seconds: 0.707, >> num_per_second: 141443 >> : Serializing Heartbeat messages from >> strings: >> times-debug-normal.txt : num: 100000, seconds: 4.749, >> num_per_second: 21057.1 >> times-debug-modified.txt : num: 100000, seconds: 2.671, >> num_per_second: 37439.2 >> times-optimized-normal.txt : num: 100000, seconds: 3.053, >> num_per_second: 32754.7 >> times-optimized-modified.txt: num: 100000, seconds: 1.782, >> num_per_second: 56116.7 >> : Creating NewOrderSingle messages: >> times-debug-normal.txt : num: 100000, seconds: 6.422, >> num_per_second: 15571.5 >> times-debug-modified.txt : num: 100000, seconds: 3.937, >> num_per_second: 25400.1 >> times-optimized-normal.txt : num: 100000, seconds: 4.778, >> num_per_second: 20929.3 >> times-optimized-modified.txt: num: 100000, seconds: 3.026, >> num_per_second: 33046.9 >> : Serializing NewOrderSingle messages to >> strings: >> times-debug-normal.txt : num: 100000, seconds: 6.429, >> num_per_second: 15554.5 >> times-debug-modified.txt : num: 100000, seconds: 3.84, >> num_per_second: 26041.7 >> times-optimized-normal.txt : num: 100000, seconds: 4.874, >> num_per_second: 20517 >> times-optimized-modified.txt: num: 100000, seconds: 3.029, >> num_per_second: 33014.2 >> : Serializing NewOrderSingle messages >> from strings: >> times-debug-normal.txt : num: 100000, seconds: 9.608, >> num_per_second: 10408 >> times-debug-modified.txt : num: 100000, seconds: 5.385, >> num_per_second: 18570.1 >> times-optimized-normal.txt : num: 100000, seconds: 7.202, >> num_per_second: 13885 >> times-optimized-modified.txt: num: 100000, seconds: 3.779, >> num_per_second: 26462 >> : Creating QuoteRequest messages: >> times-debug-normal.txt : num: 100000, seconds: 93.295, >> num_per_second: 1071.87 >> times-debug-modified.txt : num: 100000, seconds: 46.975, >> num_per_second: 2128.79 >> times-optimized-normal.txt : num: 100000, seconds: 61.148, >> num_per_second: 1635.38 >> times-optimized-modified.txt: num: 100000, seconds: 33.904, >> num_per_second: 2949.5 >> : Serializing QuoteRequest messages to >> strings: >> times-debug-normal.txt : num: 100000, seconds: 11.052, >> num_per_second: 9048.14 >> times-debug-modified.txt : num: 100000, seconds: 10.691, >> num_per_second: 9353.66 >> times-optimized-normal.txt : num: 100000, seconds: 5.667, >> num_per_second: 17646 >> times-optimized-modified.txt: num: 100000, seconds: 4.808, >> num_per_second: 20798.7 >> : Serializing QuoteRequest messages from >> strings: >> times-debug-normal.txt : num: 100000, seconds: 74.91, >> num_per_second: 1334.94 >> times-debug-modified.txt : num: 100000, seconds: 48.556, >> num_per_second: 2059.48 >> times-optimized-normal.txt : num: 100000, seconds: 47.944, >> num_per_second: 2085.77 >> times-optimized-modified.txt: num: 100000, seconds: 28.627, >> num_per_second: 3493.21 >> : Reading fields from QuoteRequest >> message: >> times-debug-normal.txt : num: 100000, seconds: 34.526, >> num_per_second: 2896.37 >> times-debug-modified.txt : num: 100000, seconds: 12.988, >> num_per_second: 7699.41 >> times-optimized-normal.txt : num: 100000, seconds: 21.891, >> num_per_second: 4568.09 >> times-optimized-modified.txt: num: 100000, seconds: 6.875, >> num_per_second: 14545.5 >> : Storing NewOrderSingle messages: >> times-debug-normal.txt : num: 100000, seconds: 0.765, >> num_per_second: 130719 >> times-debug-modified.txt : num: 100000, seconds: 0.71, >> num_per_second: 140845 >> times-optimized-normal.txt : num: 100000, seconds: 0.575, >> num_per_second: 173913 >> times-optimized-modified.txt: num: 100000, seconds: 0.521, >> num_per_second: 191939 >> : Validating NewOrderSingle messages with >> no data dictionary: >> times-debug-normal.txt : num: 100000, seconds: 1.489, >> num_per_second: 67159.2 >> times-debug-modified.txt : num: 100000, seconds: 0.859, >> num_per_second: 116414 >> times-optimized-normal.txt : num: 100000, seconds: 0.843, >> num_per_second: 118624 >> times-optimized-modified.txt: num: 100000, seconds: 0.426, >> num_per_second: 234742 >> : Validating NewOrderSingle messages with >> data dictionary: >> times-debug-normal.txt : num: 100000, seconds: 7.732, >> num_per_second: 12933.3 >> times-debug-modified.txt : num: 100000, seconds: 6.105, >> num_per_second: 16380 >> times-optimized-normal.txt : num: 100000, seconds: 2.485, >> num_per_second: 40241.4 >> times-optimized-modified.txt: num: 100000, seconds: 1.717, >> num_per_second: 58241.1 >> >> >> --- quickfix/src/C++/FieldConvertors.h 2004-04-29 20:58:20.000000000 >> +0100 >> +++ quickfix-debug-modified/src/C++/FieldConvertors.h 2004-08-12 >> 19:13:22.036829060 +0100 >> @@ -1,3 +1,4 @@ >> + >> /* -*- C++ -*- */ >> >> >> / >> ********************************************************************** >> ****** >> @@ -32,6 +33,76 @@ >> >> namespace FIX >> { >> +template<class T> >> +static inline char * integer_to_string (char * buf, const size_t >> len, T t) >> +{ >> + const bool is_neg = t < 0; >> + char * p = buf + len; >> + >> + *--p = '\0'; >> + >> + if (is_neg) { >> + if (t == std::numeric_limits<T>::min()) { >> + *--p = '0' + (10-t%10)%10; >> + t/=10; >> + } >> + t=-t; >> + do { >> + *--p = '0' + t % 10; >> + t /= 10; >> + } while (t > 0); >> + *--p = '-'; >> + } else { >> + do { >> + *--p = '0' + t % 10; >> + t /= 10; >> + } while (t > 0); >> + } >> + return p; >> +} >> + >> + >> + >> +template<class T> >> +static inline char * integer_to_string_padded (char * buf, >> + const size_t len, >> + T t, >> + const size_t width = 0, >> + const char padding_char = '0') >> +{ >> + if (!width) return integer_to_string (buf, len, t); >> + >> + const bool is_neg = t < 0; >> + char * p = buf + len; >> + >> + *--p = '\0'; >> + >> + if (is_neg) { >> + if (t == std::numeric_limits<T>::min()) { >> + *--p = '0' + (10-t%10)%10; >> + t/=10; >> + } >> + t=-t; >> + do { >> + *--p = '0' + t % 10; >> + t /= 10; >> + } while (t > 0); >> + if (p > buf) >> + *--p = '-'; >> + } else { >> + do { >> + *--p = '0' + t % 10; >> + t /= 10; >> + } while (t > 0); >> + } >> + const char * stop_p = buf + len - width - 1; >> + if (stop_p < buf) stop_p = buf; >> + while (p > stop_p) >> + *--p = padding_char; >> + return p; >> +} >> + >> + >> /// Empty convertor is a no-op. >> struct EmptyConvertor >> { >> @@ -46,21 +117,32 @@ >> { >> static std::string convert( long value ) >> { >> - char temp[ 12 ]; >> - memset( temp, 0, 12 * sizeof( char ) ); >> - sprintf( temp, "%d", ( int ) value ); >> - return temp; >> + // buffer is big enough for significant digits and extra digit, >> minus and null >> + char buffer [std::numeric_limits<long>::digits10 + 3]; >> + const char * const start = integer_to_string (buffer, sizeof >> (buffer), value); >> + return std::string (start, buffer + sizeof (buffer) - start - 1); >> } >> >> static bool convert( const std::string& value, long& result ) >> { >> const char * str = value.c_str(); >> - if ( *str == '-' ) ++str; >> - for ( const char * p = str; *p != 0; ++p ) >> - { >> - if ( !isdigit( *p ) ) return false; >> + bool is_neg = false; >> + long x = 0; >> + >> + if (*str == '-') { >> + is_neg = true; >> + ++str; >> } >> - result = atol( value.c_str() ); >> + >> + do { >> + const int c = *str - '0'; >> + if (c < 0 || 9 < c) return false; >> + x = 10 * x + c; >> + } while (*++str); >> + >> + if (is_neg) x = -x; >> + >> + result = x; >> return true; >> } >> >> @@ -81,9 +163,10 @@ >> throw( FieldConvertError& ) >> { >> if ( value > 255 || value < 0 ) throw FieldConvertError(); >> - std::stringstream stream; >> - stream << std::setw( 3 ) << std::setfill( '0' ) << value; >> - return stream.str(); >> + char result [4]; >> + if (integer_to_string_padded (result, sizeof(result), value, 3, >> '0') != result) >> + throw FieldConvertError(); >> + return std::string (result, 3); >> } >> >> static bool convert( const std::string& value, long& result ) >> @@ -104,53 +187,32 @@ >> static std::string convert( double value ) >> { >> char result[ 32 ]; >> - memset( result, 0, 32 * sizeof( char ) ); >> - sprintf( result, "%.15g", value ); >> - return result; >> + return std::string (result, std::sprintf( result, "%.15g", value >> )); >> } >> >> static bool convert( const std::string& value, double& result ) >> { >> - if ( !value.size() ) return false; >> - if ( value == "." ) return false; >> - >> - result = atof( const_cast < char* > ( value.c_str() ) ); >> - std::string stripped = value; >> - >> - // add leading zero if none exists >> - if ( *stripped.begin() == '.' ) >> - stripped = '0' + stripped; >> - >> - // remove extra leading zeros >> - while ( stripped.size() > 1 >> - && *(stripped.begin()) == '0' >> - && isdigit(*(stripped.begin()+1)) ) >> - { >> - stripped.erase( stripped.begin() ); >> + const char * i = value.c_str(); >> + >> + if (!*i) return false; // Catch null >> strings >> + if (*i == '-' && !*++i) return false; // Eat >> leading '-' and recheck for null string >> + >> + bool have_digit = false; >> + >> + if (std::isdigit (*i)) { >> + have_digit = true; >> + while (std::isdigit (*++i)); >> } >> >> - if ( stripped.find( '.' ) != std::string::npos ) >> - { >> - std::string::reverse_iterator r = stripped.rbegin(); >> - while ( r != stripped.rend() && ( *r == '0' || *r == '.' ) ) >> - { >> - if ( *r == '.' ) { stripped.resize( stripped.size() - 1 ); >> break; } >> - stripped.resize( stripped.size() - 1 ); r++; >> - } >> - } >> - if ( *stripped.begin() == '0' ) >> - { >> - std::string::size_type i = stripped.find_first_not_of( '0' ); >> - std::string::size_type dot = stripped.find( '.' ); >> - if ( i != dot ) >> - stripped = stripped.substr( i ); >> + if (*i == '.' && std::isdigit (*++i)) { >> + have_digit = true; >> + while (std::isdigit (*++i)); >> } >> >> - std::string converted = convert( result ); >> - if ( stripped.size() != converted.size() ) return false; >> + if (*i || !have_digit) return false; >> >> - // strcmp is being used because == operator is funky under linux >> - return ( strcmp( stripped.c_str(), converted.c_str() ) == 0 ); >> + result = std::strtod (value.c_str(), 0); >> + return true; >> } >> >> static double convert( const std::string& value ) >> @@ -169,16 +231,13 @@ >> { >> static std::string convert( char value ) >> { >> - char temp[ 2 ]; >> - temp[ 0 ] = value; >> - temp[ 1 ] = '\0'; >> - return temp; >> + return std::string (1, value); >> } >> >> static bool convert( const std::string& value, char& result ) >> { >> - if ( value.size() == 0 ) return false; >> - result = *value.c_str(); >> + if ( value.size() != 1 ) return false; >> + result = value[0]; >> return true; >> } >> >> @@ -197,15 +256,19 @@ >> struct BoolConvertor >> { >> static std::string convert( bool value ) >> - { return value ? "Y" : "N"; } >> + { >> + const char ch = value ? 'Y' : 'N'; >> + return std::string (1, ch); >> + } >> >> static bool convert( const std::string& value, bool& result ) >> { >> - if ( value == "Y" ) result = true; >> - else >> - if ( value == "N" ) result = false; >> - else >> - return false; >> + if (value.size() != 1) return false; >> + switch (value[0]) { >> + case 'Y': result = true; break; >> + case 'N': result = false; break; >> + default: return false; >> + } >> return true; >> } >> >> @@ -227,13 +290,19 @@ >> throw( FieldConvertError& ) >> { >> char result[ 18+4 ]; >> - int len = strftime( result, 18, "%Y%m%d-%H:%M:%S", value ); >> - if ( len != 17 ) throw FieldConvertError(); >> + >> + integer_to_string_padded (result , 5, static_cast<const >> tm*>(value)->tm_year + 1900, 4, '0'); >> + integer_to_string_padded (result + 4, 3, static_cast<const >> tm*>(value)->tm_mon + 1, 2, '0'); >> + integer_to_string_padded (result + 6, 3, static_cast<const >> tm*>(value)->tm_mday, 2, '0'); result[8] = '-'; >> + integer_to_string_padded (result + 9, 3, static_cast<const >> tm*>(value)->tm_hour, 2, '0'); result[11] = ':'; >> + integer_to_string_padded (result + 12, 3, static_cast<const >> tm*>(value)->tm_min, 2, '0'); result[14] = ':'; >> + integer_to_string_padded (result + 15, 3, static_cast<const >> tm*>(value)->tm_sec, 2, '0'); >> >> if(true==showMilliseconds) >> { >> - len = sprintf(result+17,".%03d",value.getMillisecond()); >> - if ( len != 4) throw FieldConvertError(); >> + result[17] = '.'; >> + if (integer_to_string_padded (result + 18, 4, >> value.getMillisecond(), 3, '0') != result + 18) >> + throw FieldConvertError(); >> } >> return result; >> } >> @@ -242,19 +311,73 @@ >> throw( FieldConvertError& ) >> { >> UtcTimeStamp result; >> - const char* val = value.c_str(); >> - const char* len = strptime( val, "%Y%m%d-%H:%M:%S", result ); >> - if ( len - val != 17 ) throw FieldConvertError(); >> - >> - // if we have milliseconds in the string, *len should be ".sss" >> - result.setMillisecond(0); >> - if(NULL != len && strlen(len)==4 && len[0] == '.') >> - { >> - int ms = atoi(&len[1]); >> - if(ms < 0 || ms > 999) throw FieldConvertError(); >> - result.setMillisecond(ms); >> + bool have_milliseconds = false; >> + >> + switch (value.size()) { >> + case 21: have_milliseconds = true; >> + case 17: break; >> + default: throw FieldConvertError(); >> } >> >> + int i = 0; >> + for (int c=0; c<8; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + if (value[i++] != '-') throw >> FieldConvertError(); >> + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + if (value[i++] != ':') throw >> FieldConvertError(); >> + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + if (value[i++] != ':') throw >> FieldConvertError(); >> + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + if (have_milliseconds) { >> + if (value[i++] != '.') throw FieldConvertError(); >> + for (int c=0; c<3; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + } >> + >> + tm & result_tm = *static_cast<tm*>(result); >> + >> + i = 0; >> + >> + result_tm.tm_year = value[i++] - '0'; >> + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; >> + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; >> + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; >> + result_tm.tm_year -= 1900; >> + >> + result_tm.tm_mon = value[i++] - '0'; >> + result_tm.tm_mon = 10 * result_tm.tm_mon + value[i++] - '0'; >> + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw >> FieldConvertError(); >> + --result_tm.tm_mon; >> + >> + result_tm.tm_mday = value[i++] - '0'; >> + result_tm.tm_mday = 10 * result_tm.tm_mday + value[i++] - '0'; >> + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw >> FieldConvertError(); >> + >> + ++i; // skip '-' >> + >> + result_tm.tm_hour = value[i++] - '0'; >> + result_tm.tm_hour = 10 * result_tm.tm_hour + value[i++] - '0'; >> + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No >> check for >= 0 as no '-' are converted here >> + >> + ++i; // skip ':' >> + >> + result_tm.tm_min = value[i++] - '0'; >> + result_tm.tm_min = 10 * result_tm.tm_min + value[i++] - '0'; >> + if (59 < result_tm.tm_min) throw FieldConvertError(); // No >> check for >= 0 as no '-' are converted here >> + >> + ++i; // skip ':' >> + >> + result_tm.tm_sec = value[i++] - '0'; >> + result_tm.tm_sec = 10 * result_tm.tm_sec + value[i++] - '0'; >> + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No >> check for >= 0 as no '-' are converted here >> + >> + if (have_milliseconds) >> + result.setMillisecond (100 * (value[i+1] - '0') + >> + 10 * (value[i+2] - '0') + >> + (value[i+3] - '0')); >> + else >> + result.setMillisecond (0); >> + >> + result_tm.tm_isdst = -1; >> + >> return result; >> } >> }; >> @@ -266,13 +389,16 @@ >> throw( FieldConvertError& ) >> { >> char result[ 9+4 ]; >> - int len = strftime( result, 9, "%H:%M:%S", value ); >> - if ( len != 8 ) throw FieldConvertError(); >> + >> + integer_to_string_padded (result , 3, static_cast<const >> tm*>(value)->tm_hour, 2, '0'); result[2] = ':'; >> + integer_to_string_padded (result + 3, 3, static_cast<const >> tm*>(value)->tm_min, 2, '0'); result[5] = ':'; >> + integer_to_string_padded (result + 6, 3, static_cast<const >> tm*>(value)->tm_sec, 2, '0'); >> >> if(true==showMilliseconds) >> { >> - len = sprintf(result+8,".%03d",value.getMillisecond()); >> - if ( len != 4) throw FieldConvertError(); >> + result[8] = '.'; >> + if (integer_to_string_padded (result + 9, 4, >> value.getMillisecond(), 3, '0') != result + 9) >> + throw FieldConvertError(); >> } >> >> return result; >> @@ -282,19 +408,52 @@ >> throw( FieldConvertError& ) >> { >> UtcTimeOnly result; >> - const char* val = value.c_str(); >> - const char* len = strptime( val, "%H:%M:%S", result ); >> - if ( len - val != 8 ) throw FieldConvertError(); >> - >> - // if we have milliseconds in the string, *len should be ".sss" >> - result.setMillisecond(0); >> - if(NULL != len && strlen(len)==4 && len[0] == '.') >> - { >> - int ms = atoi(&len[1]); >> - if(ms < 0 || ms > 999) throw FieldConvertError(); >> - result.setMillisecond(ms); >> + bool have_milliseconds = false; >> + >> + switch (value.size()) { >> + case 12: have_milliseconds = true; >> + case 8: break; >> + default: throw FieldConvertError(); >> + } >> + >> + int i = 0; >> + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + if (value[i++] != ':') throw >> FieldConvertError(); >> + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + if (value[i++] != ':') throw >> FieldConvertError(); >> + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + if (have_milliseconds) { >> + // ++i instead of i++ skips the '.' separator >> + for (int c=0; c<3; ++c) if (!std::isdigit(value[++i])) throw >> FieldConvertError(); >> } >> >> + tm & result_tm = *static_cast<tm*>(result); >> + >> + i = 0; >> + >> + result_tm.tm_hour = value[i++] - '0'; >> + result_tm.tm_hour = 10 * result_tm.tm_hour + value[i++] - '0'; >> + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No >> check for >= 0 as no '-' are converted here >> + ++i; // skip ':' >> + >> + result_tm.tm_min = value[i++] - '0'; >> + result_tm.tm_min = 10 * result_tm.tm_min + value[i++] - '0'; >> + if (59 < result_tm.tm_min) throw FieldConvertError(); // No >> check for >= 0 as no '-' are converted here >> + ++i; // skip ':' >> + >> + result_tm.tm_sec = value[i++] - '0'; >> + result_tm.tm_sec = 10 * result_tm.tm_sec + value[i++] - '0'; >> + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No >> check for >= 0 as no '-' are converted here >> + >> + if (have_milliseconds) >> + result.setMillisecond (100 * (value[i+1] - '0') + >> + 10 * (value[i+2] - '0') + >> + (value[i+3] - '0')); >> + else >> + result.setMillisecond (0); >> + >> + result_tm.tm_isdst = -1; >> + >> return result; >> } >> }; >> @@ -306,8 +465,9 @@ >> throw( FieldConvertError& ) >> { >> char result[ 9 ]; >> - int len = strftime( result, 9, "%Y%m%d", value ); >> - if ( len != 8 ) throw FieldConvertError(); >> + integer_to_string_padded (result , 5, static_cast<const >> tm*>(value)->tm_year + 1900, 4, '0'); >> + integer_to_string_padded (result + 4, 3, static_cast<const >> tm*>(value)->tm_mon + 1, 2, '0'); >> + integer_to_string_padded (result + 6, 3, static_cast<const >> tm*>(value)->tm_mday, 2, '0'); >> return result; >> } >> >> @@ -315,9 +475,34 @@ >> throw( FieldConvertError& ) >> { >> UtcDate result; >> - const char* val = value.c_str(); >> - const char* len = strptime( val, "%Y%m%d", result ); >> - if ( len - val != 8 ) throw FieldConvertError(); >> + >> + if (value.size() != 8) throw FieldConvertError(); >> + >> + int i = 0; >> + for (int c=0; c<8; ++c) if (!std::isdigit(value[i++])) throw >> FieldConvertError(); >> + >> + tm & result_tm = *static_cast<tm*>(result); >> + >> + i = 0; >> + >> + result_tm.tm_year = value[i++] - '0'; >> + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; >> + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; >> + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; >> + result_tm.tm_year -= 1900; >> + >> + result_tm.tm_mon = value[i++] - '0'; >> + result_tm.tm_mon = 10 * result_tm.tm_mon + value[i++] - '0'; >> + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw >> FieldConvertError(); >> + --result_tm.tm_mon; >> + >> + result_tm.tm_mday = value[i++] - '0'; >> + result_tm.tm_mday = 10 * result_tm.tm_mday + value[i++] - '0'; >> + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw >> FieldConvertError(); >> + ++i; // skip '-' >> + >> + result_tm.tm_isdst = -1; >> + >> return result; >> } >> }; >> >> >> <font face="Times New Roman" size="3"> >> <p>------------------------------------------------------------------- >> -----------</p> >> <p> This email is intended only for the use of the individual(s) to >> whom it is addressed and may be privileged and confidential. >> Unauthorised use or disclosure is prohibited. If you receive this >> e-mail in error, please advise immediately and delete the original >> message. This message may have been altered without your or our >> knowledge and the sender does not accept any liability for any errors >> or omissions in the message.</p> >> <p>====================================================</p> >> </font> >> >> >> >> ------------------------------------------------------- >> SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media >> 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 >> Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. >> http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 >> _______________________________________________ >> Quickfix-developers mailing list >> Qui...@li... >> https://lists.sourceforge.net/lists/listinfo/quickfix-developers >> > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Oren M. <or...@qu...> - 2004-08-13 16:09:53
|
Somehow you got the NoQuoteEntries (295) in the main message body as=20 well as within the repeating group. --oren > (8=3DFIX.4.4 > =A0=A0 9=3D128?35=3Di > =A0=A0 34=3D57 > =A0=A0 49=3DCLIENT1 > =A0=A0 52=3D20040813-12:05:59.000 > =A0=A0 56=3DTW > =A0=A0 117=3DID1 > =A0=A0 295=3D2 <-- THIS SHOULD NOT BE HERE > =A0=A0 299=3DID > =A0=A0 299=3DID3 > =A0=A0 296=3D2?302=3DID2?304=3D2?295=3D2?302=3DID4?304=3D2?295=3D2?10=3D= 041?) |
From: Oren M. <or...@qu...> - 2004-08-13 15:53:45
|
BTW those comparisons are against what was in the repository, which may have something to do with it. They were already optimized a great deal from 1.7.1. But I'm still not sure why the double conversions didn't improve since that was unchanged from 1.7.1 --oren On Aug 12, 2004, at 2:13 PM, Peterson, Kristofer wrote: > QuickFIX Documentation: > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > I have optimized some of the field convertors in FieldConvertors.h and > have achieved substantial improvements in performance (generally 50% - > 200% faster). I include a patch against the FieldConvertors.h file > from quickfix-1.7.1. > > The code is admittedly 'C-ish', however no interface has been changed > and I believe the results speak for themselves. > > Replacing strtod() in the double to string conversion would probably > be a significant win, although I don't know of any efficient > algorithms for this conversion. > > Finally, time stamp conversions should probably be added to pt as well. > > Cheers, > > - Kris > > The times were obtained from pt running on an AthlonXP 2500 running > Linux kernel 2.6.7 compiled with g++ 3.3.4. 'normal' builds used the > existing FieldConvertors.h, 'modified' builds used the modified > FieldConvertors.h. > > Optimization flags for the builds were as follows: > > quickfix-debug-modified/Makefile:CFLAGS = -g -Wall > quickfix-debug-normal/Makefile:CFLAGS = -g -Wall > quickfix-optimized-modified/Makefile:CFLAGS = -g -O3 -ffast-math > -mcpu=athlon-xp -Wall > quickfix-optimized-normal/Makefile:CFLAGS = -g -O3 -ffast-math > -mcpu=athlon-xp -Wall > > times-debug-normal.txt : peterson@karl src $ ./pt -c 100000 > times-debug-modified.txt : peterson@karl src $ ./pt -c 100000 > times-optimized-normal.txt : peterson@karl src $ ./pt -c 100000 > times-optimized-modified.txt: peterson@karl src $ ./pt -c 100000 > > : Converting integers to strings: > times-debug-normal.txt : num: 100000, seconds: 0.259, > num_per_second: 386100 > times-debug-modified.txt : num: 100000, seconds: 0.032, > num_per_second: 3.125e+06 > times-optimized-normal.txt : num: 100000, seconds: 0.183, > num_per_second: 546448 > times-optimized-modified.txt: num: 100000, seconds: 0.026, > num_per_second: 3.84615e+06 > : Converting strings to integers: > times-debug-normal.txt : num: 100000, seconds: 0.024, > num_per_second: 4.16667e+06 > times-debug-modified.txt : num: 100000, seconds: 0.008, > num_per_second: 1.25e+07 > times-optimized-normal.txt : num: 100000, seconds: 0.016, > num_per_second: 6.25e+06 > times-optimized-modified.txt: num: 100000, seconds: 0.004, > num_per_second: 2.5e+07 > : Converting doubles to strings: > times-debug-normal.txt : num: 100000, seconds: 0.711, > num_per_second: 140647 > times-debug-modified.txt : num: 100000, seconds: 0.243, > num_per_second: 411523 > times-optimized-normal.txt : num: 100000, seconds: 0.531, > num_per_second: 188324 > times-optimized-modified.txt: num: 100000, seconds: 0.236, > num_per_second: 423729 > : Converting strings to doubles: > times-debug-normal.txt : num: 100000, seconds: 0.987, > num_per_second: 101317 > times-debug-modified.txt : num: 100000, seconds: 0.058, > num_per_second: 1.72414e+06 > times-optimized-normal.txt : num: 100000, seconds: 0.725, > num_per_second: 137931 > times-optimized-modified.txt: num: 100000, seconds: 0.062, > num_per_second: 1.6129e+06 > : Creating Heartbeat messages: > times-debug-normal.txt : num: 100000, seconds: 1.823, > num_per_second: 54854.6 > times-debug-modified.txt : num: 100000, seconds: 1.166, > num_per_second: 85763.3 > times-optimized-normal.txt : num: 100000, seconds: 1.242, > num_per_second: 80515.3 > times-optimized-modified.txt: num: 100000, seconds: 0.825, > num_per_second: 121212 > : Serializing Heartbeat messages to > strings: > times-debug-normal.txt : num: 100000, seconds: 2.35, > num_per_second: 42553.2 > times-debug-modified.txt : num: 100000, seconds: 1.198, > num_per_second: 83472.5 > times-optimized-normal.txt : num: 100000, seconds: 1.425, > num_per_second: 70175.4 > times-optimized-modified.txt: num: 100000, seconds: 0.707, > num_per_second: 141443 > : Serializing Heartbeat messages from > strings: > times-debug-normal.txt : num: 100000, seconds: 4.749, > num_per_second: 21057.1 > times-debug-modified.txt : num: 100000, seconds: 2.671, > num_per_second: 37439.2 > times-optimized-normal.txt : num: 100000, seconds: 3.053, > num_per_second: 32754.7 > times-optimized-modified.txt: num: 100000, seconds: 1.782, > num_per_second: 56116.7 > : Creating NewOrderSingle messages: > times-debug-normal.txt : num: 100000, seconds: 6.422, > num_per_second: 15571.5 > times-debug-modified.txt : num: 100000, seconds: 3.937, > num_per_second: 25400.1 > times-optimized-normal.txt : num: 100000, seconds: 4.778, > num_per_second: 20929.3 > times-optimized-modified.txt: num: 100000, seconds: 3.026, > num_per_second: 33046.9 > : Serializing NewOrderSingle messages to > strings: > times-debug-normal.txt : num: 100000, seconds: 6.429, > num_per_second: 15554.5 > times-debug-modified.txt : num: 100000, seconds: 3.84, > num_per_second: 26041.7 > times-optimized-normal.txt : num: 100000, seconds: 4.874, > num_per_second: 20517 > times-optimized-modified.txt: num: 100000, seconds: 3.029, > num_per_second: 33014.2 > : Serializing NewOrderSingle messages from > strings: > times-debug-normal.txt : num: 100000, seconds: 9.608, > num_per_second: 10408 > times-debug-modified.txt : num: 100000, seconds: 5.385, > num_per_second: 18570.1 > times-optimized-normal.txt : num: 100000, seconds: 7.202, > num_per_second: 13885 > times-optimized-modified.txt: num: 100000, seconds: 3.779, > num_per_second: 26462 > : Creating QuoteRequest messages: > times-debug-normal.txt : num: 100000, seconds: 93.295, > num_per_second: 1071.87 > times-debug-modified.txt : num: 100000, seconds: 46.975, > num_per_second: 2128.79 > times-optimized-normal.txt : num: 100000, seconds: 61.148, > num_per_second: 1635.38 > times-optimized-modified.txt: num: 100000, seconds: 33.904, > num_per_second: 2949.5 > : Serializing QuoteRequest messages to > strings: > times-debug-normal.txt : num: 100000, seconds: 11.052, > num_per_second: 9048.14 > times-debug-modified.txt : num: 100000, seconds: 10.691, > num_per_second: 9353.66 > times-optimized-normal.txt : num: 100000, seconds: 5.667, > num_per_second: 17646 > times-optimized-modified.txt: num: 100000, seconds: 4.808, > num_per_second: 20798.7 > : Serializing QuoteRequest messages from > strings: > times-debug-normal.txt : num: 100000, seconds: 74.91, > num_per_second: 1334.94 > times-debug-modified.txt : num: 100000, seconds: 48.556, > num_per_second: 2059.48 > times-optimized-normal.txt : num: 100000, seconds: 47.944, > num_per_second: 2085.77 > times-optimized-modified.txt: num: 100000, seconds: 28.627, > num_per_second: 3493.21 > : Reading fields from QuoteRequest message: > times-debug-normal.txt : num: 100000, seconds: 34.526, > num_per_second: 2896.37 > times-debug-modified.txt : num: 100000, seconds: 12.988, > num_per_second: 7699.41 > times-optimized-normal.txt : num: 100000, seconds: 21.891, > num_per_second: 4568.09 > times-optimized-modified.txt: num: 100000, seconds: 6.875, > num_per_second: 14545.5 > : Storing NewOrderSingle messages: > times-debug-normal.txt : num: 100000, seconds: 0.765, > num_per_second: 130719 > times-debug-modified.txt : num: 100000, seconds: 0.71, > num_per_second: 140845 > times-optimized-normal.txt : num: 100000, seconds: 0.575, > num_per_second: 173913 > times-optimized-modified.txt: num: 100000, seconds: 0.521, > num_per_second: 191939 > : Validating NewOrderSingle messages with > no data dictionary: > times-debug-normal.txt : num: 100000, seconds: 1.489, > num_per_second: 67159.2 > times-debug-modified.txt : num: 100000, seconds: 0.859, > num_per_second: 116414 > times-optimized-normal.txt : num: 100000, seconds: 0.843, > num_per_second: 118624 > times-optimized-modified.txt: num: 100000, seconds: 0.426, > num_per_second: 234742 > : Validating NewOrderSingle messages with > data dictionary: > times-debug-normal.txt : num: 100000, seconds: 7.732, > num_per_second: 12933.3 > times-debug-modified.txt : num: 100000, seconds: 6.105, > num_per_second: 16380 > times-optimized-normal.txt : num: 100000, seconds: 2.485, > num_per_second: 40241.4 > times-optimized-modified.txt: num: 100000, seconds: 1.717, > num_per_second: 58241.1 > > > --- quickfix/src/C++/FieldConvertors.h 2004-04-29 20:58:20.000000000 > +0100 > +++ quickfix-debug-modified/src/C++/FieldConvertors.h 2004-08-12 > 19:13:22.036829060 +0100 > @@ -1,3 +1,4 @@ > + > /* -*- C++ -*- */ > > > / > *********************************************************************** > ***** > @@ -32,6 +33,76 @@ > > namespace FIX > { > +template<class T> > +static inline char * integer_to_string (char * buf, const size_t len, > T t) > +{ > + const bool is_neg = t < 0; > + char * p = buf + len; > + > + *--p = '\0'; > + > + if (is_neg) { > + if (t == std::numeric_limits<T>::min()) { > + *--p = '0' + (10-t%10)%10; > + t/=10; > + } > + t=-t; > + do { > + *--p = '0' + t % 10; > + t /= 10; > + } while (t > 0); > + *--p = '-'; > + } else { > + do { > + *--p = '0' + t % 10; > + t /= 10; > + } while (t > 0); > + } > + return p; > +} > + > + > + > +template<class T> > +static inline char * integer_to_string_padded (char * buf, > + const size_t len, > + T t, > + const size_t width = 0, > + const char padding_char = '0') > +{ > + if (!width) return integer_to_string (buf, len, t); > + > + const bool is_neg = t < 0; > + char * p = buf + len; > + > + *--p = '\0'; > + > + if (is_neg) { > + if (t == std::numeric_limits<T>::min()) { > + *--p = '0' + (10-t%10)%10; > + t/=10; > + } > + t=-t; > + do { > + *--p = '0' + t % 10; > + t /= 10; > + } while (t > 0); > + if (p > buf) > + *--p = '-'; > + } else { > + do { > + *--p = '0' + t % 10; > + t /= 10; > + } while (t > 0); > + } > + const char * stop_p = buf + len - width - 1; > + if (stop_p < buf) stop_p = buf; > + while (p > stop_p) > + *--p = padding_char; > + return p; > +} > + > + > /// Empty convertor is a no-op. > struct EmptyConvertor > { > @@ -46,21 +117,32 @@ > { > static std::string convert( long value ) > { > - char temp[ 12 ]; > - memset( temp, 0, 12 * sizeof( char ) ); > - sprintf( temp, "%d", ( int ) value ); > - return temp; > + // buffer is big enough for significant digits and extra digit, > minus and null > + char buffer [std::numeric_limits<long>::digits10 + 3]; > + const char * const start = integer_to_string (buffer, sizeof > (buffer), value); > + return std::string (start, buffer + sizeof (buffer) - start - 1); > } > > static bool convert( const std::string& value, long& result ) > { > const char * str = value.c_str(); > - if ( *str == '-' ) ++str; > - for ( const char * p = str; *p != 0; ++p ) > - { > - if ( !isdigit( *p ) ) return false; > + bool is_neg = false; > + long x = 0; > + > + if (*str == '-') { > + is_neg = true; > + ++str; > } > - result = atol( value.c_str() ); > + > + do { > + const int c = *str - '0'; > + if (c < 0 || 9 < c) return false; > + x = 10 * x + c; > + } while (*++str); > + > + if (is_neg) x = -x; > + > + result = x; > return true; > } > > @@ -81,9 +163,10 @@ > throw( FieldConvertError& ) > { > if ( value > 255 || value < 0 ) throw FieldConvertError(); > - std::stringstream stream; > - stream << std::setw( 3 ) << std::setfill( '0' ) << value; > - return stream.str(); > + char result [4]; > + if (integer_to_string_padded (result, sizeof(result), value, 3, > '0') != result) > + throw FieldConvertError(); > + return std::string (result, 3); > } > > static bool convert( const std::string& value, long& result ) > @@ -104,53 +187,32 @@ > static std::string convert( double value ) > { > char result[ 32 ]; > - memset( result, 0, 32 * sizeof( char ) ); > - sprintf( result, "%.15g", value ); > - return result; > + return std::string (result, std::sprintf( result, "%.15g", value > )); > } > > static bool convert( const std::string& value, double& result ) > { > - if ( !value.size() ) return false; > - if ( value == "." ) return false; > - > - result = atof( const_cast < char* > ( value.c_str() ) ); > - std::string stripped = value; > - > - // add leading zero if none exists > - if ( *stripped.begin() == '.' ) > - stripped = '0' + stripped; > - > - // remove extra leading zeros > - while ( stripped.size() > 1 > - && *(stripped.begin()) == '0' > - && isdigit(*(stripped.begin()+1)) ) > - { > - stripped.erase( stripped.begin() ); > + const char * i = value.c_str(); > + > + if (!*i) return false; // Catch null > strings > + if (*i == '-' && !*++i) return false; // Eat leading > '-' and recheck for null string > + > + bool have_digit = false; > + > + if (std::isdigit (*i)) { > + have_digit = true; > + while (std::isdigit (*++i)); > } > > - if ( stripped.find( '.' ) != std::string::npos ) > - { > - std::string::reverse_iterator r = stripped.rbegin(); > - while ( r != stripped.rend() && ( *r == '0' || *r == '.' ) ) > - { > - if ( *r == '.' ) { stripped.resize( stripped.size() - 1 ); > break; } > - stripped.resize( stripped.size() - 1 ); r++; > - } > - } > - if ( *stripped.begin() == '0' ) > - { > - std::string::size_type i = stripped.find_first_not_of( '0' ); > - std::string::size_type dot = stripped.find( '.' ); > - if ( i != dot ) > - stripped = stripped.substr( i ); > + if (*i == '.' && std::isdigit (*++i)) { > + have_digit = true; > + while (std::isdigit (*++i)); > } > > - std::string converted = convert( result ); > - if ( stripped.size() != converted.size() ) return false; > + if (*i || !have_digit) return false; > > - // strcmp is being used because == operator is funky under linux > - return ( strcmp( stripped.c_str(), converted.c_str() ) == 0 ); > + result = std::strtod (value.c_str(), 0); > + return true; > } > > static double convert( const std::string& value ) > @@ -169,16 +231,13 @@ > { > static std::string convert( char value ) > { > - char temp[ 2 ]; > - temp[ 0 ] = value; > - temp[ 1 ] = '\0'; > - return temp; > + return std::string (1, value); > } > > static bool convert( const std::string& value, char& result ) > { > - if ( value.size() == 0 ) return false; > - result = *value.c_str(); > + if ( value.size() != 1 ) return false; > + result = value[0]; > return true; > } > > @@ -197,15 +256,19 @@ > struct BoolConvertor > { > static std::string convert( bool value ) > - { return value ? "Y" : "N"; } > + { > + const char ch = value ? 'Y' : 'N'; > + return std::string (1, ch); > + } > > static bool convert( const std::string& value, bool& result ) > { > - if ( value == "Y" ) result = true; > - else > - if ( value == "N" ) result = false; > - else > - return false; > + if (value.size() != 1) return false; > + switch (value[0]) { > + case 'Y': result = true; break; > + case 'N': result = false; break; > + default: return false; > + } > return true; > } > > @@ -227,13 +290,19 @@ > throw( FieldConvertError& ) > { > char result[ 18+4 ]; > - int len = strftime( result, 18, "%Y%m%d-%H:%M:%S", value ); > - if ( len != 17 ) throw FieldConvertError(); > + > + integer_to_string_padded (result , 5, static_cast<const > tm*>(value)->tm_year + 1900, 4, '0'); > + integer_to_string_padded (result + 4, 3, static_cast<const > tm*>(value)->tm_mon + 1, 2, '0'); > + integer_to_string_padded (result + 6, 3, static_cast<const > tm*>(value)->tm_mday, 2, '0'); result[8] = '-'; > + integer_to_string_padded (result + 9, 3, static_cast<const > tm*>(value)->tm_hour, 2, '0'); result[11] = ':'; > + integer_to_string_padded (result + 12, 3, static_cast<const > tm*>(value)->tm_min, 2, '0'); result[14] = ':'; > + integer_to_string_padded (result + 15, 3, static_cast<const > tm*>(value)->tm_sec, 2, '0'); > > if(true==showMilliseconds) > { > - len = sprintf(result+17,".%03d",value.getMillisecond()); > - if ( len != 4) throw FieldConvertError(); > + result[17] = '.'; > + if (integer_to_string_padded (result + 18, 4, > value.getMillisecond(), 3, '0') != result + 18) > + throw FieldConvertError(); > } > return result; > } > @@ -242,19 +311,73 @@ > throw( FieldConvertError& ) > { > UtcTimeStamp result; > - const char* val = value.c_str(); > - const char* len = strptime( val, "%Y%m%d-%H:%M:%S", result ); > - if ( len - val != 17 ) throw FieldConvertError(); > - > - // if we have milliseconds in the string, *len should be ".sss" > - result.setMillisecond(0); > - if(NULL != len && strlen(len)==4 && len[0] == '.') > - { > - int ms = atoi(&len[1]); > - if(ms < 0 || ms > 999) throw FieldConvertError(); > - result.setMillisecond(ms); > + bool have_milliseconds = false; > + > + switch (value.size()) { > + case 21: have_milliseconds = true; > + case 17: break; > + default: throw FieldConvertError(); > } > > + int i = 0; > + for (int c=0; c<8; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != '-') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != ':') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != ':') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (have_milliseconds) { > + if (value[i++] != '.') throw FieldConvertError(); > + for (int c=0; c<3; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + } > + > + tm & result_tm = *static_cast<tm*>(result); > + > + i = 0; > + > + result_tm.tm_year = value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year -= 1900; > + > + result_tm.tm_mon = value[i++] - '0'; > + result_tm.tm_mon = 10 * result_tm.tm_mon + value[i++] - '0'; > + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw > FieldConvertError(); > + --result_tm.tm_mon; > + > + result_tm.tm_mday = value[i++] - '0'; > + result_tm.tm_mday = 10 * result_tm.tm_mday + value[i++] - '0'; > + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw > FieldConvertError(); > + > + ++i; // skip '-' > + > + result_tm.tm_hour = value[i++] - '0'; > + result_tm.tm_hour = 10 * result_tm.tm_hour + value[i++] - '0'; > + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No > check for >= 0 as no '-' are converted here > + > + ++i; // skip ':' > + > + result_tm.tm_min = value[i++] - '0'; > + result_tm.tm_min = 10 * result_tm.tm_min + value[i++] - '0'; > + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check > for >= 0 as no '-' are converted here > + > + ++i; // skip ':' > + > + result_tm.tm_sec = value[i++] - '0'; > + result_tm.tm_sec = 10 * result_tm.tm_sec + value[i++] - '0'; > + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check > for >= 0 as no '-' are converted here > + > + if (have_milliseconds) > + result.setMillisecond (100 * (value[i+1] - '0') + > + 10 * (value[i+2] - '0') + > + (value[i+3] - '0')); > + else > + result.setMillisecond (0); > + > + result_tm.tm_isdst = -1; > + > return result; > } > }; > @@ -266,13 +389,16 @@ > throw( FieldConvertError& ) > { > char result[ 9+4 ]; > - int len = strftime( result, 9, "%H:%M:%S", value ); > - if ( len != 8 ) throw FieldConvertError(); > + > + integer_to_string_padded (result , 3, static_cast<const > tm*>(value)->tm_hour, 2, '0'); result[2] = ':'; > + integer_to_string_padded (result + 3, 3, static_cast<const > tm*>(value)->tm_min, 2, '0'); result[5] = ':'; > + integer_to_string_padded (result + 6, 3, static_cast<const > tm*>(value)->tm_sec, 2, '0'); > > if(true==showMilliseconds) > { > - len = sprintf(result+8,".%03d",value.getMillisecond()); > - if ( len != 4) throw FieldConvertError(); > + result[8] = '.'; > + if (integer_to_string_padded (result + 9, 4, > value.getMillisecond(), 3, '0') != result + 9) > + throw FieldConvertError(); > } > > return result; > @@ -282,19 +408,52 @@ > throw( FieldConvertError& ) > { > UtcTimeOnly result; > - const char* val = value.c_str(); > - const char* len = strptime( val, "%H:%M:%S", result ); > - if ( len - val != 8 ) throw FieldConvertError(); > - > - // if we have milliseconds in the string, *len should be ".sss" > - result.setMillisecond(0); > - if(NULL != len && strlen(len)==4 && len[0] == '.') > - { > - int ms = atoi(&len[1]); > - if(ms < 0 || ms > 999) throw FieldConvertError(); > - result.setMillisecond(ms); > + bool have_milliseconds = false; > + > + switch (value.size()) { > + case 12: have_milliseconds = true; > + case 8: break; > + default: throw FieldConvertError(); > + } > + > + int i = 0; > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != ':') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != ':') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (have_milliseconds) { > + // ++i instead of i++ skips the '.' separator > + for (int c=0; c<3; ++c) if (!std::isdigit(value[++i])) throw > FieldConvertError(); > } > > + tm & result_tm = *static_cast<tm*>(result); > + > + i = 0; > + > + result_tm.tm_hour = value[i++] - '0'; > + result_tm.tm_hour = 10 * result_tm.tm_hour + value[i++] - '0'; > + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No > check for >= 0 as no '-' are converted here > + ++i; // skip ':' > + > + result_tm.tm_min = value[i++] - '0'; > + result_tm.tm_min = 10 * result_tm.tm_min + value[i++] - '0'; > + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check > for >= 0 as no '-' are converted here > + ++i; // skip ':' > + > + result_tm.tm_sec = value[i++] - '0'; > + result_tm.tm_sec = 10 * result_tm.tm_sec + value[i++] - '0'; > + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check > for >= 0 as no '-' are converted here > + > + if (have_milliseconds) > + result.setMillisecond (100 * (value[i+1] - '0') + > + 10 * (value[i+2] - '0') + > + (value[i+3] - '0')); > + else > + result.setMillisecond (0); > + > + result_tm.tm_isdst = -1; > + > return result; > } > }; > @@ -306,8 +465,9 @@ > throw( FieldConvertError& ) > { > char result[ 9 ]; > - int len = strftime( result, 9, "%Y%m%d", value ); > - if ( len != 8 ) throw FieldConvertError(); > + integer_to_string_padded (result , 5, static_cast<const > tm*>(value)->tm_year + 1900, 4, '0'); > + integer_to_string_padded (result + 4, 3, static_cast<const > tm*>(value)->tm_mon + 1, 2, '0'); > + integer_to_string_padded (result + 6, 3, static_cast<const > tm*>(value)->tm_mday, 2, '0'); > return result; > } > > @@ -315,9 +475,34 @@ > throw( FieldConvertError& ) > { > UtcDate result; > - const char* val = value.c_str(); > - const char* len = strptime( val, "%Y%m%d", result ); > - if ( len - val != 8 ) throw FieldConvertError(); > + > + if (value.size() != 8) throw FieldConvertError(); > + > + int i = 0; > + for (int c=0; c<8; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + > + tm & result_tm = *static_cast<tm*>(result); > + > + i = 0; > + > + result_tm.tm_year = value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year -= 1900; > + > + result_tm.tm_mon = value[i++] - '0'; > + result_tm.tm_mon = 10 * result_tm.tm_mon + value[i++] - '0'; > + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw > FieldConvertError(); > + --result_tm.tm_mon; > + > + result_tm.tm_mday = value[i++] - '0'; > + result_tm.tm_mday = 10 * result_tm.tm_mday + value[i++] - '0'; > + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw > FieldConvertError(); > + ++i; // skip '-' > + > + result_tm.tm_isdst = -1; > + > return result; > } > }; > > > <font face="Times New Roman" size="3"> > <p>-------------------------------------------------------------------- > ----------</p> > <p> This email is intended only for the use of the individual(s) to > whom it is addressed and may be privileged and confidential. > Unauthorised use or disclosure is prohibited. If you receive this > e-mail in error, please advise immediately and delete the original > message. This message may have been altered without your or our > knowledge and the sender does not accept any liability for any errors > or omissions in the message.</p> > <p>====================================================</p> > </font> > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Oren M. <or...@qu...> - 2004-08-13 15:52:03
|
Thanks Kristopher, I ran these through and was able to see nice performance improvements on serializing to strings, however for some reasons the performance for serializing from strings remained unchanged on the systems I tested under. Also converting from doubles to strings showed no improvement. I tried this under a i686 Xeon and a powerpc chipsets. --oren On Aug 12, 2004, at 2:13 PM, Peterson, Kristofer wrote: > QuickFIX Documentation: > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > I have optimized some of the field convertors in FieldConvertors.h and > have achieved substantial improvements in performance (generally 50% - > 200% faster). I include a patch against the FieldConvertors.h file > from quickfix-1.7.1. > > The code is admittedly 'C-ish', however no interface has been changed > and I believe the results speak for themselves. > > Replacing strtod() in the double to string conversion would probably > be a significant win, although I don't know of any efficient > algorithms for this conversion. > > Finally, time stamp conversions should probably be added to pt as well. > > Cheers, > > - Kris > > The times were obtained from pt running on an AthlonXP 2500 running > Linux kernel 2.6.7 compiled with g++ 3.3.4. 'normal' builds used the > existing FieldConvertors.h, 'modified' builds used the modified > FieldConvertors.h. > > Optimization flags for the builds were as follows: > > quickfix-debug-modified/Makefile:CFLAGS = -g -Wall > quickfix-debug-normal/Makefile:CFLAGS = -g -Wall > quickfix-optimized-modified/Makefile:CFLAGS = -g -O3 -ffast-math > -mcpu=athlon-xp -Wall > quickfix-optimized-normal/Makefile:CFLAGS = -g -O3 -ffast-math > -mcpu=athlon-xp -Wall > > times-debug-normal.txt : peterson@karl src $ ./pt -c 100000 > times-debug-modified.txt : peterson@karl src $ ./pt -c 100000 > times-optimized-normal.txt : peterson@karl src $ ./pt -c 100000 > times-optimized-modified.txt: peterson@karl src $ ./pt -c 100000 > > : Converting integers to strings: > times-debug-normal.txt : num: 100000, seconds: 0.259, > num_per_second: 386100 > times-debug-modified.txt : num: 100000, seconds: 0.032, > num_per_second: 3.125e+06 > times-optimized-normal.txt : num: 100000, seconds: 0.183, > num_per_second: 546448 > times-optimized-modified.txt: num: 100000, seconds: 0.026, > num_per_second: 3.84615e+06 > : Converting strings to integers: > times-debug-normal.txt : num: 100000, seconds: 0.024, > num_per_second: 4.16667e+06 > times-debug-modified.txt : num: 100000, seconds: 0.008, > num_per_second: 1.25e+07 > times-optimized-normal.txt : num: 100000, seconds: 0.016, > num_per_second: 6.25e+06 > times-optimized-modified.txt: num: 100000, seconds: 0.004, > num_per_second: 2.5e+07 > : Converting doubles to strings: > times-debug-normal.txt : num: 100000, seconds: 0.711, > num_per_second: 140647 > times-debug-modified.txt : num: 100000, seconds: 0.243, > num_per_second: 411523 > times-optimized-normal.txt : num: 100000, seconds: 0.531, > num_per_second: 188324 > times-optimized-modified.txt: num: 100000, seconds: 0.236, > num_per_second: 423729 > : Converting strings to doubles: > times-debug-normal.txt : num: 100000, seconds: 0.987, > num_per_second: 101317 > times-debug-modified.txt : num: 100000, seconds: 0.058, > num_per_second: 1.72414e+06 > times-optimized-normal.txt : num: 100000, seconds: 0.725, > num_per_second: 137931 > times-optimized-modified.txt: num: 100000, seconds: 0.062, > num_per_second: 1.6129e+06 > : Creating Heartbeat messages: > times-debug-normal.txt : num: 100000, seconds: 1.823, > num_per_second: 54854.6 > times-debug-modified.txt : num: 100000, seconds: 1.166, > num_per_second: 85763.3 > times-optimized-normal.txt : num: 100000, seconds: 1.242, > num_per_second: 80515.3 > times-optimized-modified.txt: num: 100000, seconds: 0.825, > num_per_second: 121212 > : Serializing Heartbeat messages to > strings: > times-debug-normal.txt : num: 100000, seconds: 2.35, > num_per_second: 42553.2 > times-debug-modified.txt : num: 100000, seconds: 1.198, > num_per_second: 83472.5 > times-optimized-normal.txt : num: 100000, seconds: 1.425, > num_per_second: 70175.4 > times-optimized-modified.txt: num: 100000, seconds: 0.707, > num_per_second: 141443 > : Serializing Heartbeat messages from > strings: > times-debug-normal.txt : num: 100000, seconds: 4.749, > num_per_second: 21057.1 > times-debug-modified.txt : num: 100000, seconds: 2.671, > num_per_second: 37439.2 > times-optimized-normal.txt : num: 100000, seconds: 3.053, > num_per_second: 32754.7 > times-optimized-modified.txt: num: 100000, seconds: 1.782, > num_per_second: 56116.7 > : Creating NewOrderSingle messages: > times-debug-normal.txt : num: 100000, seconds: 6.422, > num_per_second: 15571.5 > times-debug-modified.txt : num: 100000, seconds: 3.937, > num_per_second: 25400.1 > times-optimized-normal.txt : num: 100000, seconds: 4.778, > num_per_second: 20929.3 > times-optimized-modified.txt: num: 100000, seconds: 3.026, > num_per_second: 33046.9 > : Serializing NewOrderSingle messages to > strings: > times-debug-normal.txt : num: 100000, seconds: 6.429, > num_per_second: 15554.5 > times-debug-modified.txt : num: 100000, seconds: 3.84, > num_per_second: 26041.7 > times-optimized-normal.txt : num: 100000, seconds: 4.874, > num_per_second: 20517 > times-optimized-modified.txt: num: 100000, seconds: 3.029, > num_per_second: 33014.2 > : Serializing NewOrderSingle messages from > strings: > times-debug-normal.txt : num: 100000, seconds: 9.608, > num_per_second: 10408 > times-debug-modified.txt : num: 100000, seconds: 5.385, > num_per_second: 18570.1 > times-optimized-normal.txt : num: 100000, seconds: 7.202, > num_per_second: 13885 > times-optimized-modified.txt: num: 100000, seconds: 3.779, > num_per_second: 26462 > : Creating QuoteRequest messages: > times-debug-normal.txt : num: 100000, seconds: 93.295, > num_per_second: 1071.87 > times-debug-modified.txt : num: 100000, seconds: 46.975, > num_per_second: 2128.79 > times-optimized-normal.txt : num: 100000, seconds: 61.148, > num_per_second: 1635.38 > times-optimized-modified.txt: num: 100000, seconds: 33.904, > num_per_second: 2949.5 > : Serializing QuoteRequest messages to > strings: > times-debug-normal.txt : num: 100000, seconds: 11.052, > num_per_second: 9048.14 > times-debug-modified.txt : num: 100000, seconds: 10.691, > num_per_second: 9353.66 > times-optimized-normal.txt : num: 100000, seconds: 5.667, > num_per_second: 17646 > times-optimized-modified.txt: num: 100000, seconds: 4.808, > num_per_second: 20798.7 > : Serializing QuoteRequest messages from > strings: > times-debug-normal.txt : num: 100000, seconds: 74.91, > num_per_second: 1334.94 > times-debug-modified.txt : num: 100000, seconds: 48.556, > num_per_second: 2059.48 > times-optimized-normal.txt : num: 100000, seconds: 47.944, > num_per_second: 2085.77 > times-optimized-modified.txt: num: 100000, seconds: 28.627, > num_per_second: 3493.21 > : Reading fields from QuoteRequest message: > times-debug-normal.txt : num: 100000, seconds: 34.526, > num_per_second: 2896.37 > times-debug-modified.txt : num: 100000, seconds: 12.988, > num_per_second: 7699.41 > times-optimized-normal.txt : num: 100000, seconds: 21.891, > num_per_second: 4568.09 > times-optimized-modified.txt: num: 100000, seconds: 6.875, > num_per_second: 14545.5 > : Storing NewOrderSingle messages: > times-debug-normal.txt : num: 100000, seconds: 0.765, > num_per_second: 130719 > times-debug-modified.txt : num: 100000, seconds: 0.71, > num_per_second: 140845 > times-optimized-normal.txt : num: 100000, seconds: 0.575, > num_per_second: 173913 > times-optimized-modified.txt: num: 100000, seconds: 0.521, > num_per_second: 191939 > : Validating NewOrderSingle messages with > no data dictionary: > times-debug-normal.txt : num: 100000, seconds: 1.489, > num_per_second: 67159.2 > times-debug-modified.txt : num: 100000, seconds: 0.859, > num_per_second: 116414 > times-optimized-normal.txt : num: 100000, seconds: 0.843, > num_per_second: 118624 > times-optimized-modified.txt: num: 100000, seconds: 0.426, > num_per_second: 234742 > : Validating NewOrderSingle messages with > data dictionary: > times-debug-normal.txt : num: 100000, seconds: 7.732, > num_per_second: 12933.3 > times-debug-modified.txt : num: 100000, seconds: 6.105, > num_per_second: 16380 > times-optimized-normal.txt : num: 100000, seconds: 2.485, > num_per_second: 40241.4 > times-optimized-modified.txt: num: 100000, seconds: 1.717, > num_per_second: 58241.1 > > > --- quickfix/src/C++/FieldConvertors.h 2004-04-29 20:58:20.000000000 > +0100 > +++ quickfix-debug-modified/src/C++/FieldConvertors.h 2004-08-12 > 19:13:22.036829060 +0100 > @@ -1,3 +1,4 @@ > + > /* -*- C++ -*- */ > > > / > *********************************************************************** > ***** > @@ -32,6 +33,76 @@ > > namespace FIX > { > +template<class T> > +static inline char * integer_to_string (char * buf, const size_t len, > T t) > +{ > + const bool is_neg = t < 0; > + char * p = buf + len; > + > + *--p = '\0'; > + > + if (is_neg) { > + if (t == std::numeric_limits<T>::min()) { > + *--p = '0' + (10-t%10)%10; > + t/=10; > + } > + t=-t; > + do { > + *--p = '0' + t % 10; > + t /= 10; > + } while (t > 0); > + *--p = '-'; > + } else { > + do { > + *--p = '0' + t % 10; > + t /= 10; > + } while (t > 0); > + } > + return p; > +} > + > + > + > +template<class T> > +static inline char * integer_to_string_padded (char * buf, > + const size_t len, > + T t, > + const size_t width = 0, > + const char padding_char = '0') > +{ > + if (!width) return integer_to_string (buf, len, t); > + > + const bool is_neg = t < 0; > + char * p = buf + len; > + > + *--p = '\0'; > + > + if (is_neg) { > + if (t == std::numeric_limits<T>::min()) { > + *--p = '0' + (10-t%10)%10; > + t/=10; > + } > + t=-t; > + do { > + *--p = '0' + t % 10; > + t /= 10; > + } while (t > 0); > + if (p > buf) > + *--p = '-'; > + } else { > + do { > + *--p = '0' + t % 10; > + t /= 10; > + } while (t > 0); > + } > + const char * stop_p = buf + len - width - 1; > + if (stop_p < buf) stop_p = buf; > + while (p > stop_p) > + *--p = padding_char; > + return p; > +} > + > + > /// Empty convertor is a no-op. > struct EmptyConvertor > { > @@ -46,21 +117,32 @@ > { > static std::string convert( long value ) > { > - char temp[ 12 ]; > - memset( temp, 0, 12 * sizeof( char ) ); > - sprintf( temp, "%d", ( int ) value ); > - return temp; > + // buffer is big enough for significant digits and extra digit, > minus and null > + char buffer [std::numeric_limits<long>::digits10 + 3]; > + const char * const start = integer_to_string (buffer, sizeof > (buffer), value); > + return std::string (start, buffer + sizeof (buffer) - start - 1); > } > > static bool convert( const std::string& value, long& result ) > { > const char * str = value.c_str(); > - if ( *str == '-' ) ++str; > - for ( const char * p = str; *p != 0; ++p ) > - { > - if ( !isdigit( *p ) ) return false; > + bool is_neg = false; > + long x = 0; > + > + if (*str == '-') { > + is_neg = true; > + ++str; > } > - result = atol( value.c_str() ); > + > + do { > + const int c = *str - '0'; > + if (c < 0 || 9 < c) return false; > + x = 10 * x + c; > + } while (*++str); > + > + if (is_neg) x = -x; > + > + result = x; > return true; > } > > @@ -81,9 +163,10 @@ > throw( FieldConvertError& ) > { > if ( value > 255 || value < 0 ) throw FieldConvertError(); > - std::stringstream stream; > - stream << std::setw( 3 ) << std::setfill( '0' ) << value; > - return stream.str(); > + char result [4]; > + if (integer_to_string_padded (result, sizeof(result), value, 3, > '0') != result) > + throw FieldConvertError(); > + return std::string (result, 3); > } > > static bool convert( const std::string& value, long& result ) > @@ -104,53 +187,32 @@ > static std::string convert( double value ) > { > char result[ 32 ]; > - memset( result, 0, 32 * sizeof( char ) ); > - sprintf( result, "%.15g", value ); > - return result; > + return std::string (result, std::sprintf( result, "%.15g", value > )); > } > > static bool convert( const std::string& value, double& result ) > { > - if ( !value.size() ) return false; > - if ( value == "." ) return false; > - > - result = atof( const_cast < char* > ( value.c_str() ) ); > - std::string stripped = value; > - > - // add leading zero if none exists > - if ( *stripped.begin() == '.' ) > - stripped = '0' + stripped; > - > - // remove extra leading zeros > - while ( stripped.size() > 1 > - && *(stripped.begin()) == '0' > - && isdigit(*(stripped.begin()+1)) ) > - { > - stripped.erase( stripped.begin() ); > + const char * i = value.c_str(); > + > + if (!*i) return false; // Catch null > strings > + if (*i == '-' && !*++i) return false; // Eat leading > '-' and recheck for null string > + > + bool have_digit = false; > + > + if (std::isdigit (*i)) { > + have_digit = true; > + while (std::isdigit (*++i)); > } > > - if ( stripped.find( '.' ) != std::string::npos ) > - { > - std::string::reverse_iterator r = stripped.rbegin(); > - while ( r != stripped.rend() && ( *r == '0' || *r == '.' ) ) > - { > - if ( *r == '.' ) { stripped.resize( stripped.size() - 1 ); > break; } > - stripped.resize( stripped.size() - 1 ); r++; > - } > - } > - if ( *stripped.begin() == '0' ) > - { > - std::string::size_type i = stripped.find_first_not_of( '0' ); > - std::string::size_type dot = stripped.find( '.' ); > - if ( i != dot ) > - stripped = stripped.substr( i ); > + if (*i == '.' && std::isdigit (*++i)) { > + have_digit = true; > + while (std::isdigit (*++i)); > } > > - std::string converted = convert( result ); > - if ( stripped.size() != converted.size() ) return false; > + if (*i || !have_digit) return false; > > - // strcmp is being used because == operator is funky under linux > - return ( strcmp( stripped.c_str(), converted.c_str() ) == 0 ); > + result = std::strtod (value.c_str(), 0); > + return true; > } > > static double convert( const std::string& value ) > @@ -169,16 +231,13 @@ > { > static std::string convert( char value ) > { > - char temp[ 2 ]; > - temp[ 0 ] = value; > - temp[ 1 ] = '\0'; > - return temp; > + return std::string (1, value); > } > > static bool convert( const std::string& value, char& result ) > { > - if ( value.size() == 0 ) return false; > - result = *value.c_str(); > + if ( value.size() != 1 ) return false; > + result = value[0]; > return true; > } > > @@ -197,15 +256,19 @@ > struct BoolConvertor > { > static std::string convert( bool value ) > - { return value ? "Y" : "N"; } > + { > + const char ch = value ? 'Y' : 'N'; > + return std::string (1, ch); > + } > > static bool convert( const std::string& value, bool& result ) > { > - if ( value == "Y" ) result = true; > - else > - if ( value == "N" ) result = false; > - else > - return false; > + if (value.size() != 1) return false; > + switch (value[0]) { > + case 'Y': result = true; break; > + case 'N': result = false; break; > + default: return false; > + } > return true; > } > > @@ -227,13 +290,19 @@ > throw( FieldConvertError& ) > { > char result[ 18+4 ]; > - int len = strftime( result, 18, "%Y%m%d-%H:%M:%S", value ); > - if ( len != 17 ) throw FieldConvertError(); > + > + integer_to_string_padded (result , 5, static_cast<const > tm*>(value)->tm_year + 1900, 4, '0'); > + integer_to_string_padded (result + 4, 3, static_cast<const > tm*>(value)->tm_mon + 1, 2, '0'); > + integer_to_string_padded (result + 6, 3, static_cast<const > tm*>(value)->tm_mday, 2, '0'); result[8] = '-'; > + integer_to_string_padded (result + 9, 3, static_cast<const > tm*>(value)->tm_hour, 2, '0'); result[11] = ':'; > + integer_to_string_padded (result + 12, 3, static_cast<const > tm*>(value)->tm_min, 2, '0'); result[14] = ':'; > + integer_to_string_padded (result + 15, 3, static_cast<const > tm*>(value)->tm_sec, 2, '0'); > > if(true==showMilliseconds) > { > - len = sprintf(result+17,".%03d",value.getMillisecond()); > - if ( len != 4) throw FieldConvertError(); > + result[17] = '.'; > + if (integer_to_string_padded (result + 18, 4, > value.getMillisecond(), 3, '0') != result + 18) > + throw FieldConvertError(); > } > return result; > } > @@ -242,19 +311,73 @@ > throw( FieldConvertError& ) > { > UtcTimeStamp result; > - const char* val = value.c_str(); > - const char* len = strptime( val, "%Y%m%d-%H:%M:%S", result ); > - if ( len - val != 17 ) throw FieldConvertError(); > - > - // if we have milliseconds in the string, *len should be ".sss" > - result.setMillisecond(0); > - if(NULL != len && strlen(len)==4 && len[0] == '.') > - { > - int ms = atoi(&len[1]); > - if(ms < 0 || ms > 999) throw FieldConvertError(); > - result.setMillisecond(ms); > + bool have_milliseconds = false; > + > + switch (value.size()) { > + case 21: have_milliseconds = true; > + case 17: break; > + default: throw FieldConvertError(); > } > > + int i = 0; > + for (int c=0; c<8; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != '-') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != ':') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != ':') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (have_milliseconds) { > + if (value[i++] != '.') throw FieldConvertError(); > + for (int c=0; c<3; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + } > + > + tm & result_tm = *static_cast<tm*>(result); > + > + i = 0; > + > + result_tm.tm_year = value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year -= 1900; > + > + result_tm.tm_mon = value[i++] - '0'; > + result_tm.tm_mon = 10 * result_tm.tm_mon + value[i++] - '0'; > + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw > FieldConvertError(); > + --result_tm.tm_mon; > + > + result_tm.tm_mday = value[i++] - '0'; > + result_tm.tm_mday = 10 * result_tm.tm_mday + value[i++] - '0'; > + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw > FieldConvertError(); > + > + ++i; // skip '-' > + > + result_tm.tm_hour = value[i++] - '0'; > + result_tm.tm_hour = 10 * result_tm.tm_hour + value[i++] - '0'; > + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No > check for >= 0 as no '-' are converted here > + > + ++i; // skip ':' > + > + result_tm.tm_min = value[i++] - '0'; > + result_tm.tm_min = 10 * result_tm.tm_min + value[i++] - '0'; > + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check > for >= 0 as no '-' are converted here > + > + ++i; // skip ':' > + > + result_tm.tm_sec = value[i++] - '0'; > + result_tm.tm_sec = 10 * result_tm.tm_sec + value[i++] - '0'; > + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check > for >= 0 as no '-' are converted here > + > + if (have_milliseconds) > + result.setMillisecond (100 * (value[i+1] - '0') + > + 10 * (value[i+2] - '0') + > + (value[i+3] - '0')); > + else > + result.setMillisecond (0); > + > + result_tm.tm_isdst = -1; > + > return result; > } > }; > @@ -266,13 +389,16 @@ > throw( FieldConvertError& ) > { > char result[ 9+4 ]; > - int len = strftime( result, 9, "%H:%M:%S", value ); > - if ( len != 8 ) throw FieldConvertError(); > + > + integer_to_string_padded (result , 3, static_cast<const > tm*>(value)->tm_hour, 2, '0'); result[2] = ':'; > + integer_to_string_padded (result + 3, 3, static_cast<const > tm*>(value)->tm_min, 2, '0'); result[5] = ':'; > + integer_to_string_padded (result + 6, 3, static_cast<const > tm*>(value)->tm_sec, 2, '0'); > > if(true==showMilliseconds) > { > - len = sprintf(result+8,".%03d",value.getMillisecond()); > - if ( len != 4) throw FieldConvertError(); > + result[8] = '.'; > + if (integer_to_string_padded (result + 9, 4, > value.getMillisecond(), 3, '0') != result + 9) > + throw FieldConvertError(); > } > > return result; > @@ -282,19 +408,52 @@ > throw( FieldConvertError& ) > { > UtcTimeOnly result; > - const char* val = value.c_str(); > - const char* len = strptime( val, "%H:%M:%S", result ); > - if ( len - val != 8 ) throw FieldConvertError(); > - > - // if we have milliseconds in the string, *len should be ".sss" > - result.setMillisecond(0); > - if(NULL != len && strlen(len)==4 && len[0] == '.') > - { > - int ms = atoi(&len[1]); > - if(ms < 0 || ms > 999) throw FieldConvertError(); > - result.setMillisecond(ms); > + bool have_milliseconds = false; > + > + switch (value.size()) { > + case 12: have_milliseconds = true; > + case 8: break; > + default: throw FieldConvertError(); > + } > + > + int i = 0; > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != ':') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (value[i++] != ':') throw > FieldConvertError(); > + for (int c=0; c<2; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + if (have_milliseconds) { > + // ++i instead of i++ skips the '.' separator > + for (int c=0; c<3; ++c) if (!std::isdigit(value[++i])) throw > FieldConvertError(); > } > > + tm & result_tm = *static_cast<tm*>(result); > + > + i = 0; > + > + result_tm.tm_hour = value[i++] - '0'; > + result_tm.tm_hour = 10 * result_tm.tm_hour + value[i++] - '0'; > + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No > check for >= 0 as no '-' are converted here > + ++i; // skip ':' > + > + result_tm.tm_min = value[i++] - '0'; > + result_tm.tm_min = 10 * result_tm.tm_min + value[i++] - '0'; > + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check > for >= 0 as no '-' are converted here > + ++i; // skip ':' > + > + result_tm.tm_sec = value[i++] - '0'; > + result_tm.tm_sec = 10 * result_tm.tm_sec + value[i++] - '0'; > + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check > for >= 0 as no '-' are converted here > + > + if (have_milliseconds) > + result.setMillisecond (100 * (value[i+1] - '0') + > + 10 * (value[i+2] - '0') + > + (value[i+3] - '0')); > + else > + result.setMillisecond (0); > + > + result_tm.tm_isdst = -1; > + > return result; > } > }; > @@ -306,8 +465,9 @@ > throw( FieldConvertError& ) > { > char result[ 9 ]; > - int len = strftime( result, 9, "%Y%m%d", value ); > - if ( len != 8 ) throw FieldConvertError(); > + integer_to_string_padded (result , 5, static_cast<const > tm*>(value)->tm_year + 1900, 4, '0'); > + integer_to_string_padded (result + 4, 3, static_cast<const > tm*>(value)->tm_mon + 1, 2, '0'); > + integer_to_string_padded (result + 6, 3, static_cast<const > tm*>(value)->tm_mday, 2, '0'); > return result; > } > > @@ -315,9 +475,34 @@ > throw( FieldConvertError& ) > { > UtcDate result; > - const char* val = value.c_str(); > - const char* len = strptime( val, "%Y%m%d", result ); > - if ( len - val != 8 ) throw FieldConvertError(); > + > + if (value.size() != 8) throw FieldConvertError(); > + > + int i = 0; > + for (int c=0; c<8; ++c) if (!std::isdigit(value[i++])) throw > FieldConvertError(); > + > + tm & result_tm = *static_cast<tm*>(result); > + > + i = 0; > + > + result_tm.tm_year = value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year = 10 * result_tm.tm_year + value[i++] - '0'; > + result_tm.tm_year -= 1900; > + > + result_tm.tm_mon = value[i++] - '0'; > + result_tm.tm_mon = 10 * result_tm.tm_mon + value[i++] - '0'; > + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw > FieldConvertError(); > + --result_tm.tm_mon; > + > + result_tm.tm_mday = value[i++] - '0'; > + result_tm.tm_mday = 10 * result_tm.tm_mday + value[i++] - '0'; > + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw > FieldConvertError(); > + ++i; // skip '-' > + > + result_tm.tm_isdst = -1; > + > return result; > } > }; > > > <font face="Times New Roman" size="3"> > <p>-------------------------------------------------------------------- > ----------</p> > <p> This email is intended only for the use of the individual(s) to > whom it is addressed and may be privileged and confidential. > Unauthorised use or disclosure is prohibited. If you receive this > e-mail in error, please advise immediately and delete the original > message. This message may have been altered without your or our > knowledge and the sender does not accept any liability for any errors > or omissions in the message.</p> > <p>====================================================</p> > </font> > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Joy B. <jo...@cy...> - 2004-08-13 14:05:10
|
i seem to be having a problem handling repeating groups (NoQuoteEntries) = as also groups nested within groups. for the message type "MassQuote" i am getting the following output:=20 <20040813-12:05:59, FIX.4.4:TW->CLIENT1, incoming> (8=3DFIX.4.4 9=3D128?35=3Di 34=3D57 49=3DCLIENT1 52=3D20040813-12:05:59.000 56=3DTW=20 117=3DID1 295=3D2 299=3DID 299=3DID3 = 296=3D2?302=3DID2?304=3D2?295=3D2?302=3DID4?304=3D2?295=3D2?10=3D041?) <20040813-12:05:59, FIX.4.4:TW->CLIENT1, event> (Message 57 Rejected: Tag not defined for this message type:295) <20040813-12:05:59, FIX.4.4:TW->CLIENT1, outgoing> (8=3DFIX.4.4 9=3D120 35=3D3 34=3D57 49=3DTW 52=3D20040813-12:05:59.000 56=3DCLIENT1 45=3D57 58=3DTag not defined for this message type 371=3D295 372=3Di 373=3D2 10=3D249) The client side code is as follows: FIX44::MassQuote Application::queryMassQuote44() { FIX44::MassQuote massQuote(queryQuoteID()); massQuote.set( queryNoQuoteSets() ); =20 FIX44::MassQuote::NoQuoteSets noQuoteSetsGroup; =20 noQuoteSetsGroup.set( queryQuoteSetID () ); noQuoteSetsGroup.set( queryTotNoQuoteEntries() ); noQuoteSetsGroup.set( queryNoQuoteEntries() ); massQuote.addGroup( noQuoteSetsGroup ); =20 FIX44::MassQuote::NoQuoteSets::NoQuoteEntries noQuoteEntriesGroup; noQuoteEntriesGroup.set(queryQuoteEntryID () ); noQuoteSetsGroup.addGroup( noQuoteEntriesGroup ); noQuoteSetsGroup.set( queryQuoteSetID () ); noQuoteSetsGroup.set( queryTotNoQuoteEntries() ); noQuoteSetsGroup.set( queryNoQuoteEntries() ); massQuote.addGroup( noQuoteSetsGroup ); noQuoteEntriesGroup.set(queryQuoteEntryID () ); noQuoteSetsGroup.addGroup( noQuoteEntriesGroup ); queryHeader( massQuote.getHeader() ); return massQuote; } the server side code is as follows: void Application::onMessage( const FIX44::MassQuote& message, const FIX::SessionID& sessionID ) { FIX::QuoteID quoteID; FIX::NoQuoteSets noQuoteSets; =20 message.get( quoteID ); message.get( noQuoteSets ); FIX44::MassQuote::NoQuoteSets noQuoteSetsGroup; FIX::QuoteSetID quoteSetID; FIX::TotNoQuoteEntries totNoQuoteEntries; FIX::NoQuoteEntries noQuoteEntries; message.getGroup(1, noQuoteSetsGroup); noQuoteSetsGroup.getField( quoteSetID ); noQuoteSetsGroup.getField( totNoQuoteEntries ); noQuoteSetsGroup.getField( noQuoteEntries ); FIX44::MassQuote::NoQuoteSets::NoQuoteEntries noQuoteEntriesGroup1; FIX::QuoteEntryID quoteEntryID; message.getGroup(1, noQuoteEntriesGroup1); noQuoteEntriesGroup1.getField( quoteEntryID ); =20 message.getGroup(2, noQuoteSetsGroup); noQuoteSetsGroup.getField( quoteSetID ); noQuoteSetsGroup.getField( totNoQuoteEntries ); noQuoteSetsGroup.getField( noQuoteEntries ); FIX44::MassQuote::NoQuoteSets::NoQuoteEntries noQuoteEntriesGroup2; message.getGroup(1, noQuoteEntriesGroup2); noQuoteEntriesGroup2.getField( quoteEntryID ); =20 FIX44::MassQuoteAcknowledgement massQuoteAcknowledgement =3D = FIX44::MassQuoteAcknowledgement ( FIX::QuoteStatus( 0 )); try { FIX::Session::sendToTarget( massQuoteAcknowledgement, sessionID ); } catch ( FIX::SessionNotFound& ) {} } |
From: Oren M. <or...@qu...> - 2004-08-12 19:51:26
|
BTW, these are the versions being used currently to create an official QuickFIX release: aclocal (GNU automake) 1.7.9 autoheader (GNU Autoconf) 2.57 libtoolize (GNU libtool) 1.5 automake (GNU automake) 1.7.9 autoconf (GNU Autoconf) 2.57 On Aug 12, 2004, at 2:20 PM, Peterson, Kristofer wrote: > QuickFIX Documentation: > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > I've pulled the latest CVS tree but running 'bootstrap' results in the > following: > > lsdev2:~/cvsroot/quickfix $ ./bootstrap > aclocal... > aclocal: configure.in: 6: macro `AM_DISABLE_STATIC' not found in > library > aclocal: configure.in: 14: macro `AM_PROG_LIBTOOL' not found in library > aclocal: configure.in: 122: macro `AM_PATH_XML' not found in library > autoheader... > autoheader: error: AC_CONFIG_HEADERS not found in configure.in > libtoolize... > automake... > configure.in: 14: required file `./ltconfig' not found > configure.in: 5: required file `./config.h.in' not found > autoconf... > Now run configure with any arguments necessary > lsdev2:~/cvsroot/quickfix $ ./configure > ./configure: line 1309: syntax error near unexpected token > `AM_INIT_AUTOMAKE(quickfix,' > ./configure: line 1309: `AM_INIT_AUTOMAKE(quickfix, 1.8.0)' > > I ran all of the commands in 'bootstrap' with a '--version' options; > this is what I got: > > aclocal (GNU automake) 1.4 > autoheader (GNU Autoconf) 2.59 > libtoolize (GNU libtool) 1.5.2 > automake (GNU automake) 1.4 > autoconf (GNU Autoconf) 2.59 > > Are these versions current enough to build QuickFIX? > > I'm also running this on Solaris/SPARC, which shouldn't matter but may > be causing a problem. > > Any help would be appreciated. > > Cheers, > > - Kris > > > <font face="Times New Roman" size="3"> > <p>-------------------------------------------------------------------- > ----------</p> > <p> This email is intended only for the use of the individual(s) to > whom it is addressed and may be privileged and confidential. > Unauthorised use or disclosure is prohibited. If you receive this > e-mail in error, please advise immediately and delete the original > message. This message may have been altered without your or our > knowledge and the sender does not accept any liability for any errors > or omissions in the message.</p> > <p>====================================================</p> > </font> > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Oren M. <or...@qu...> - 2004-08-12 19:47:35
|
This first two errors (AM_DISABLE_STATIC and AM_PROG_LIBTOOL), acan mean that automake and libtool were not installed to the same prefix. But I think it may also be that you're version of Automake is quite old (the latest version is 1.9). I would suggest upgrading at least that package. As for AM_PATH_XML, this is probably because you do not have the devel package for libxml2 installed. --oren On Aug 12, 2004, at 2:20 PM, Peterson, Kristofer wrote: > QuickFIX Documentation: > http://www.quickfixengine.org/quickfix/doc/html/index.html > QuickFIX FAQ: > http://www.quickfixengine.org/wikifix/index.php?QuickFixFAQ > QuickFIX Support: http://www.quickfixengine.org/services.html > > I've pulled the latest CVS tree but running 'bootstrap' results in the > following: > > lsdev2:~/cvsroot/quickfix $ ./bootstrap > aclocal... > aclocal: configure.in: 6: macro `AM_DISABLE_STATIC' not found in > library > aclocal: configure.in: 14: macro `AM_PROG_LIBTOOL' not found in library > aclocal: configure.in: 122: macro `AM_PATH_XML' not found in library > autoheader... > autoheader: error: AC_CONFIG_HEADERS not found in configure.in > libtoolize... > automake... > configure.in: 14: required file `./ltconfig' not found > configure.in: 5: required file `./config.h.in' not found > autoconf... > Now run configure with any arguments necessary > lsdev2:~/cvsroot/quickfix $ ./configure > ./configure: line 1309: syntax error near unexpected token > `AM_INIT_AUTOMAKE(quickfix,' > ./configure: line 1309: `AM_INIT_AUTOMAKE(quickfix, 1.8.0)' > > I ran all of the commands in 'bootstrap' with a '--version' options; > this is what I got: > > aclocal (GNU automake) 1.4 > autoheader (GNU Autoconf) 2.59 > libtoolize (GNU libtool) 1.5.2 > automake (GNU automake) 1.4 > autoconf (GNU Autoconf) 2.59 > > Are these versions current enough to build QuickFIX? > > I'm also running this on Solaris/SPARC, which shouldn't matter but may > be causing a problem. > > Any help would be appreciated. > > Cheers, > > - Kris > > > <font face="Times New Roman" size="3"> > <p>-------------------------------------------------------------------- > ----------</p> > <p> This email is intended only for the use of the individual(s) to > whom it is addressed and may be privileged and confidential. > Unauthorised use or disclosure is prohibited. If you receive this > e-mail in error, please advise immediately and delete the original > message. This message may have been altered without your or our > knowledge and the sender does not accept any liability for any errors > or omissions in the message.</p> > <p>====================================================</p> > </font> > > > > ------------------------------------------------------- > SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media > 100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33 > Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift. > http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285 > _______________________________________________ > Quickfix-developers mailing list > Qui...@li... > https://lists.sourceforge.net/lists/listinfo/quickfix-developers > |
From: Peterson, K. <kri...@rb...> - 2004-08-12 19:21:06
|
I've pulled the latest CVS tree but running 'bootstrap' results in the foll= owing: lsdev2:~/cvsroot/quickfix $ ./bootstrap aclocal... aclocal: configure.in: 6: macro `AM_DISABLE_STATIC' not found in library aclocal: configure.in: 14: macro `AM_PROG_LIBTOOL' not found in library aclocal: configure.in: 122: macro `AM_PATH_XML' not found in library autoheader... autoheader: error: AC_CONFIG_HEADERS not found in configure.in libtoolize... automake... configure.in: 14: required file `./ltconfig' not found configure.in: 5: required file `./config.h.in' not found autoconf... Now run configure with any arguments necessary lsdev2:~/cvsroot/quickfix $ ./configure ./configure: line 1309: syntax error near unexpected token `AM_INIT_AUTOMAK= E(quickfix,' ./configure: line 1309: `AM_INIT_AUTOMAKE(quickfix, 1.8.0)' I ran all of the commands in 'bootstrap' with a '--version' options; this i= s what I got: aclocal (GNU automake) 1.4 autoheader (GNU Autoconf) 2.59 libtoolize (GNU libtool) 1.5.2 automake (GNU automake) 1.4 autoconf (GNU Autoconf) 2.59 Are these versions current enough to build QuickFIX? I'm also running this on Solaris/SPARC, which shouldn't matter but may be c= ausing a problem. Any help would be appreciated. Cheers, - Kris <font face=3D"Times New Roman" size=3D"3"> <p>------------------------------------------------------------------------= ------</p> <p> This email is intended only for the use of the individual(s) to whom it= is addressed and may be privileged and confidential. Unauthorised use or d= isclosure is prohibited. If you receive this e-mail in error, please advise= immediately and delete the original message. This message may have been al= tered without your or our knowledge and the sender does not accept any liab= ility for any errors or omissions in the message.</p> <p>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D</p> </font> |
From: Peterson, K. <kri...@rb...> - 2004-08-12 19:13:59
|
I have optimized some of the field convertors in FieldConvertors.h and have= achieved substantial improvements in performance (generally 50% - 200% fas= ter). I include a patch against the FieldConvertors.h file from quickfix-1.= 7.1. The code is admittedly 'C-ish', however no interface has been changed and I= believe the results speak for themselves. Replacing strtod() in the double to string conversion would probably be a s= ignificant win, although I don't know of any efficient algorithms for this = conversion. Finally, time stamp conversions should probably be added to pt as well. Cheers, - Kris The times were obtained from pt running on an AthlonXP 2500 running Linux k= ernel 2.6.7 compiled with g++ 3.3.4. 'normal' builds used the existing Fiel= dConvertors.h, 'modified' builds used the modified FieldConvertors.h. Optimization flags for the builds were as follows: quickfix-debug-modified/Makefile:CFLAGS =3D -g -Wall quickfix-debug-normal/Makefile:CFLAGS =3D -g -Wall quickfix-optimized-modified/Makefile:CFLAGS =3D -g -O3 -ffast-math -mcpu=3D= athlon-xp -Wall quickfix-optimized-normal/Makefile:CFLAGS =3D -g -O3 -ffast-math -mcpu=3Dat= hlon-xp -Wall times-debug-normal.txt : peterson@karl src $ ./pt -c 100000 times-debug-modified.txt : peterson@karl src $ ./pt -c 100000 times-optimized-normal.txt : peterson@karl src $ ./pt -c 100000 times-optimized-modified.txt: peterson@karl src $ ./pt -c 100000 : Converting integers to strings: times-debug-normal.txt : num: 100000, seconds: 0.259, num_per_seco= nd: 386100 times-debug-modified.txt : num: 100000, seconds: 0.032, num_per_seco= nd: 3.125e+06 times-optimized-normal.txt : num: 100000, seconds: 0.183, num_per_seco= nd: 546448 times-optimized-modified.txt: num: 100000, seconds: 0.026, num_per_seco= nd: 3.84615e+06 : Converting strings to integers: times-debug-normal.txt : num: 100000, seconds: 0.024, num_per_seco= nd: 4.16667e+06 times-debug-modified.txt : num: 100000, seconds: 0.008, num_per_seco= nd: 1.25e+07 times-optimized-normal.txt : num: 100000, seconds: 0.016, num_per_seco= nd: 6.25e+06 times-optimized-modified.txt: num: 100000, seconds: 0.004, num_per_seco= nd: 2.5e+07 : Converting doubles to strings: times-debug-normal.txt : num: 100000, seconds: 0.711, num_per_seco= nd: 140647 times-debug-modified.txt : num: 100000, seconds: 0.243, num_per_seco= nd: 411523 times-optimized-normal.txt : num: 100000, seconds: 0.531, num_per_seco= nd: 188324 times-optimized-modified.txt: num: 100000, seconds: 0.236, num_per_seco= nd: 423729 : Converting strings to doubles: times-debug-normal.txt : num: 100000, seconds: 0.987, num_per_seco= nd: 101317 times-debug-modified.txt : num: 100000, seconds: 0.058, num_per_seco= nd: 1.72414e+06 times-optimized-normal.txt : num: 100000, seconds: 0.725, num_per_seco= nd: 137931 times-optimized-modified.txt: num: 100000, seconds: 0.062, num_per_seco= nd: 1.6129e+06 : Creating Heartbeat messages: times-debug-normal.txt : num: 100000, seconds: 1.823, num_per_seco= nd: 54854.6 times-debug-modified.txt : num: 100000, seconds: 1.166, num_per_seco= nd: 85763.3 times-optimized-normal.txt : num: 100000, seconds: 1.242, num_per_seco= nd: 80515.3 times-optimized-modified.txt: num: 100000, seconds: 0.825, num_per_seco= nd: 121212 : Serializing Heartbeat messages to strings: times-debug-normal.txt : num: 100000, seconds: 2.35, num_per_secon= d: 42553.2 times-debug-modified.txt : num: 100000, seconds: 1.198, num_per_seco= nd: 83472.5 times-optimized-normal.txt : num: 100000, seconds: 1.425, num_per_seco= nd: 70175.4 times-optimized-modified.txt: num: 100000, seconds: 0.707, num_per_seco= nd: 141443 : Serializing Heartbeat messages from strings: times-debug-normal.txt : num: 100000, seconds: 4.749, num_per_seco= nd: 21057.1 times-debug-modified.txt : num: 100000, seconds: 2.671, num_per_seco= nd: 37439.2 times-optimized-normal.txt : num: 100000, seconds: 3.053, num_per_seco= nd: 32754.7 times-optimized-modified.txt: num: 100000, seconds: 1.782, num_per_seco= nd: 56116.7 : Creating NewOrderSingle messages: times-debug-normal.txt : num: 100000, seconds: 6.422, num_per_seco= nd: 15571.5 times-debug-modified.txt : num: 100000, seconds: 3.937, num_per_seco= nd: 25400.1 times-optimized-normal.txt : num: 100000, seconds: 4.778, num_per_seco= nd: 20929.3 times-optimized-modified.txt: num: 100000, seconds: 3.026, num_per_seco= nd: 33046.9 : Serializing NewOrderSingle messages to string= s: times-debug-normal.txt : num: 100000, seconds: 6.429, num_per_seco= nd: 15554.5 times-debug-modified.txt : num: 100000, seconds: 3.84, num_per_secon= d: 26041.7 times-optimized-normal.txt : num: 100000, seconds: 4.874, num_per_seco= nd: 20517 times-optimized-modified.txt: num: 100000, seconds: 3.029, num_per_seco= nd: 33014.2 : Serializing NewOrderSingle messages from stri= ngs: times-debug-normal.txt : num: 100000, seconds: 9.608, num_per_seco= nd: 10408 times-debug-modified.txt : num: 100000, seconds: 5.385, num_per_seco= nd: 18570.1 times-optimized-normal.txt : num: 100000, seconds: 7.202, num_per_seco= nd: 13885 times-optimized-modified.txt: num: 100000, seconds: 3.779, num_per_seco= nd: 26462 : Creating QuoteRequest messages: times-debug-normal.txt : num: 100000, seconds: 93.295, num_per_sec= ond: 1071.87 times-debug-modified.txt : num: 100000, seconds: 46.975, num_per_sec= ond: 2128.79 times-optimized-normal.txt : num: 100000, seconds: 61.148, num_per_sec= ond: 1635.38 times-optimized-modified.txt: num: 100000, seconds: 33.904, num_per_sec= ond: 2949.5 : Serializing QuoteRequest messages to strings: times-debug-normal.txt : num: 100000, seconds: 11.052, num_per_sec= ond: 9048.14 times-debug-modified.txt : num: 100000, seconds: 10.691, num_per_sec= ond: 9353.66 times-optimized-normal.txt : num: 100000, seconds: 5.667, num_per_seco= nd: 17646 times-optimized-modified.txt: num: 100000, seconds: 4.808, num_per_seco= nd: 20798.7 : Serializing QuoteRequest messages from string= s: times-debug-normal.txt : num: 100000, seconds: 74.91, num_per_seco= nd: 1334.94 times-debug-modified.txt : num: 100000, seconds: 48.556, num_per_sec= ond: 2059.48 times-optimized-normal.txt : num: 100000, seconds: 47.944, num_per_sec= ond: 2085.77 times-optimized-modified.txt: num: 100000, seconds: 28.627, num_per_sec= ond: 3493.21 : Reading fields from QuoteRequest message: times-debug-normal.txt : num: 100000, seconds: 34.526, num_per_sec= ond: 2896.37 times-debug-modified.txt : num: 100000, seconds: 12.988, num_per_sec= ond: 7699.41 times-optimized-normal.txt : num: 100000, seconds: 21.891, num_per_sec= ond: 4568.09 times-optimized-modified.txt: num: 100000, seconds: 6.875, num_per_seco= nd: 14545.5 : Storing NewOrderSingle messages: times-debug-normal.txt : num: 100000, seconds: 0.765, num_per_seco= nd: 130719 times-debug-modified.txt : num: 100000, seconds: 0.71, num_per_secon= d: 140845 times-optimized-normal.txt : num: 100000, seconds: 0.575, num_per_seco= nd: 173913 times-optimized-modified.txt: num: 100000, seconds: 0.521, num_per_seco= nd: 191939 : Validating NewOrderSingle messages with no da= ta dictionary: times-debug-normal.txt : num: 100000, seconds: 1.489, num_per_seco= nd: 67159.2 times-debug-modified.txt : num: 100000, seconds: 0.859, num_per_seco= nd: 116414 times-optimized-normal.txt : num: 100000, seconds: 0.843, num_per_seco= nd: 118624 times-optimized-modified.txt: num: 100000, seconds: 0.426, num_per_seco= nd: 234742 : Validating NewOrderSingle messages with data = dictionary: times-debug-normal.txt : num: 100000, seconds: 7.732, num_per_seco= nd: 12933.3 times-debug-modified.txt : num: 100000, seconds: 6.105, num_per_seco= nd: 16380 times-optimized-normal.txt : num: 100000, seconds: 2.485, num_per_seco= nd: 40241.4 times-optimized-modified.txt: num: 100000, seconds: 1.717, num_per_seco= nd: 58241.1 --- quickfix/src/C++/FieldConvertors.h 2004-04-29 20:58:20.000000000 +0100 +++ quickfix-debug-modified/src/C++/FieldConvertors.h 2004-08-12 19:13:22= .036829060 +0100 @@ -1,3 +1,4 @@ + /* -*- C++ -*- */ /*************************************************************************= *** @@ -32,6 +33,76 @@ namespace FIX { +template<class T> +static inline char * integer_to_string (char * buf, const size_t len, T t) +{ + const bool is_neg =3D t < 0; + char * p =3D buf + len; + + *--p =3D '\0'; + + if (is_neg) { + if (t =3D=3D std::numeric_limits<T>::min()) { + *--p =3D '0' + (10-t%10)%10; + t/=3D10; + } + t=3D-t; + do { + *--p =3D '0' + t % 10; + t /=3D 10; + } while (t > 0); + *--p =3D '-'; + } else { + do { + *--p =3D '0' + t % 10; + t /=3D 10; + } while (t > 0); + } + return p; +} + + + +template<class T> +static inline char * integer_to_string_padded (char * buf, + const size_t len, + T t, + const size_t width =3D 0, + const char padding_char =3D '0') +{ + if (!width) return integer_to_string (buf, len, t); + + const bool is_neg =3D t < 0; + char * p =3D buf + len; + + *--p =3D '\0'; + + if (is_neg) { + if (t =3D=3D std::numeric_limits<T>::min()) { + *--p =3D '0' + (10-t%10)%10; + t/=3D10; + } + t=3D-t; + do { + *--p =3D '0' + t % 10; + t /=3D 10; + } while (t > 0); + if (p > buf) + *--p =3D '-'; + } else { + do { + *--p =3D '0' + t % 10; + t /=3D 10; + } while (t > 0); + } + const char * stop_p =3D buf + len - width - 1; + if (stop_p < buf) stop_p =3D buf; + while (p > stop_p) + *--p =3D padding_char; + return p; +} + + /// Empty convertor is a no-op. struct EmptyConvertor { @@ -46,21 +117,32 @@ { static std::string convert( long value ) { - char temp[ 12 ]; - memset( temp, 0, 12 * sizeof( char ) ); - sprintf( temp, "%d", ( int ) value ); - return temp; + // buffer is big enough for significant digits and extra digit, minus = and null + char buffer [std::numeric_limits<long>::digits10 + 3]; + const char * const start =3D integer_to_string (buffer, sizeof (buffer= ), value); + return std::string (start, buffer + sizeof (buffer) - start - 1); } static bool convert( const std::string& value, long& result ) { const char * str =3D value.c_str(); - if ( *str =3D=3D '-' ) ++str; - for ( const char * p =3D str; *p !=3D 0; ++p ) - { - if ( !isdigit( *p ) ) return false; + bool is_neg =3D false; + long x =3D 0; + + if (*str =3D=3D '-') { + is_neg =3D true; + ++str; } - result =3D atol( value.c_str() ); + + do { + const int c =3D *str - '0'; + if (c < 0 || 9 < c) return false; + x =3D 10 * x + c; + } while (*++str); + + if (is_neg) x =3D -x; + + result =3D x; return true; } @@ -81,9 +163,10 @@ throw( FieldConvertError& ) { if ( value > 255 || value < 0 ) throw FieldConvertError(); - std::stringstream stream; - stream << std::setw( 3 ) << std::setfill( '0' ) << value; - return stream.str(); + char result [4]; + if (integer_to_string_padded (result, sizeof(result), value, 3, '0') != =3D result) + throw FieldConvertError(); + return std::string (result, 3); } static bool convert( const std::string& value, long& result ) @@ -104,53 +187,32 @@ static std::string convert( double value ) { char result[ 32 ]; - memset( result, 0, 32 * sizeof( char ) ); - sprintf( result, "%.15g", value ); - return result; + return std::string (result, std::sprintf( result, "%.15g", value )); } static bool convert( const std::string& value, double& result ) { - if ( !value.size() ) return false; - if ( value =3D=3D "." ) return false; - - result =3D atof( const_cast < char* > ( value.c_str() ) ); - std::string stripped =3D value; - - // add leading zero if none exists - if ( *stripped.begin() =3D=3D '.' ) - stripped =3D '0' + stripped; - - // remove extra leading zeros - while ( stripped.size() > 1 - && *(stripped.begin()) =3D=3D '0' - && isdigit(*(stripped.begin()+1)) ) - { - stripped.erase( stripped.begin() ); + const char * i =3D value.c_str(); + + if (!*i) return false; // Catch null strin= gs + if (*i =3D=3D '-' && !*++i) return false; // Eat leading = '-' and recheck for null string + + bool have_digit =3D false; + + if (std::isdigit (*i)) { + have_digit =3D true; + while (std::isdigit (*++i)); } - if ( stripped.find( '.' ) !=3D std::string::npos ) - { - std::string::reverse_iterator r =3D stripped.rbegin(); - while ( r !=3D stripped.rend() && ( *r =3D=3D '0' || *r =3D=3D '.' )= ) - { - if ( *r =3D=3D '.' ) { stripped.resize( stripped.size() - 1 ); bre= ak; } - stripped.resize( stripped.size() - 1 ); r++; - } - } - if ( *stripped.begin() =3D=3D '0' ) - { - std::string::size_type i =3D stripped.find_first_not_of( '0' ); - std::string::size_type dot =3D stripped.find( '.' ); - if ( i !=3D dot ) - stripped =3D stripped.substr( i ); + if (*i =3D=3D '.' && std::isdigit (*++i)) { + have_digit =3D true; + while (std::isdigit (*++i)); } - std::string converted =3D convert( result ); - if ( stripped.size() !=3D converted.size() ) return false; + if (*i || !have_digit) return false; - // strcmp is being used because =3D=3D operator is funky under linux - return ( strcmp( stripped.c_str(), converted.c_str() ) =3D=3D 0 ); + result =3D std::strtod (value.c_str(), 0); + return true; } static double convert( const std::string& value ) @@ -169,16 +231,13 @@ { static std::string convert( char value ) { - char temp[ 2 ]; - temp[ 0 ] =3D value; - temp[ 1 ] =3D '\0'; - return temp; + return std::string (1, value); } static bool convert( const std::string& value, char& result ) { - if ( value.size() =3D=3D 0 ) return false; - result =3D *value.c_str(); + if ( value.size() !=3D 1 ) return false; + result =3D value[0]; return true; } @@ -197,15 +256,19 @@ struct BoolConvertor { static std::string convert( bool value ) - { return value ? "Y" : "N"; } + { + const char ch =3D value ? 'Y' : 'N'; + return std::string (1, ch); + } static bool convert( const std::string& value, bool& result ) { - if ( value =3D=3D "Y" ) result =3D true; - else - if ( value =3D=3D "N" ) result =3D false; - else - return false; + if (value.size() !=3D 1) return false; + switch (value[0]) { + case 'Y': result =3D true; break; + case 'N': result =3D false; break; + default: return false; + } return true; } @@ -227,13 +290,19 @@ throw( FieldConvertError& ) { char result[ 18+4 ]; - int len =3D strftime( result, 18, "%Y%m%d-%H:%M:%S", value ); - if ( len !=3D 17 ) throw FieldConvertError(); + + integer_to_string_padded (result , 5, static_cast<const tm*>(value= )->tm_year + 1900, 4, '0'); + integer_to_string_padded (result + 4, 3, static_cast<const tm*>(value= )->tm_mon + 1, 2, '0'); + integer_to_string_padded (result + 6, 3, static_cast<const tm*>(value= )->tm_mday, 2, '0'); result[8] =3D '-'; + integer_to_string_padded (result + 9, 3, static_cast<const tm*>(value= )->tm_hour, 2, '0'); result[11] =3D ':'; + integer_to_string_padded (result + 12, 3, static_cast<const tm*>(value= )->tm_min, 2, '0'); result[14] =3D ':'; + integer_to_string_padded (result + 15, 3, static_cast<const tm*>(value= )->tm_sec, 2, '0'); if(true=3D=3DshowMilliseconds) { - len =3D sprintf(result+17,".%03d",value.getMillisecond()); - if ( len !=3D 4) throw FieldConvertError(); + result[17] =3D '.'; + if (integer_to_string_padded (result + 18, 4, value.getMillisecond()= , 3, '0') !=3D result + 18) + throw FieldConvertError(); } return result; } @@ -242,19 +311,73 @@ throw( FieldConvertError& ) { UtcTimeStamp result; - const char* val =3D value.c_str(); - const char* len =3D strptime( val, "%Y%m%d-%H:%M:%S", result ); - if ( len - val !=3D 17 ) throw FieldConvertError(); - - // if we have milliseconds in the string, *len should be ".sss" - result.setMillisecond(0); - if(NULL !=3D len && strlen(len)=3D=3D4 && len[0] =3D=3D '.') - { - int ms =3D atoi(&len[1]); - if(ms < 0 || ms > 999) throw FieldConvertError(); - result.setMillisecond(ms); + bool have_milliseconds =3D false; + + switch (value.size()) { + case 21: have_milliseconds =3D true; + case 17: break; + default: throw FieldConvertError(); } + int i =3D 0; + for (int c=3D0; c<8; ++c) if (!std::isdigit(value[i++])) throw FieldCo= nvertError(); + if (value[i++] !=3D '-') throw FieldConvertErr= or(); + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw FieldCo= nvertError(); + if (value[i++] !=3D ':') throw FieldConvertErr= or(); + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw FieldCo= nvertError(); + if (value[i++] !=3D ':') throw FieldConvertErr= or(); + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw FieldCo= nvertError(); + if (have_milliseconds) { + if (value[i++] !=3D '.') throw FieldConvertError(); + for (int c=3D0; c<3; ++c) if (!std::isdigit(value[i++])) throw Field= ConvertError(); + } + + tm & result_tm =3D *static_cast<tm*>(result); + + i =3D 0; + + result_tm.tm_year =3D value[i++] - '0'; + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; + result_tm.tm_year -=3D 1900; + + result_tm.tm_mon =3D value[i++] - '0'; + result_tm.tm_mon =3D 10 * result_tm.tm_mon + value[i++] - '0'; + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw FieldConvertE= rror(); + --result_tm.tm_mon; + + result_tm.tm_mday =3D value[i++] - '0'; + result_tm.tm_mday =3D 10 * result_tm.tm_mday + value[i++] - '0'; + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw FieldConver= tError(); + + ++i; // skip '-' + + result_tm.tm_hour =3D value[i++] - '0'; + result_tm.tm_hour =3D 10 * result_tm.tm_hour + value[i++] - '0'; + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No check for= >=3D 0 as no '-' are converted here + + ++i; // skip ':' + + result_tm.tm_min =3D value[i++] - '0'; + result_tm.tm_min =3D 10 * result_tm.tm_min + value[i++] - '0'; + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check for = >=3D 0 as no '-' are converted here + + ++i; // skip ':' + + result_tm.tm_sec =3D value[i++] - '0'; + result_tm.tm_sec =3D 10 * result_tm.tm_sec + value[i++] - '0'; + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check for = >=3D 0 as no '-' are converted here + + if (have_milliseconds) + result.setMillisecond (100 * (value[i+1] - '0') + + 10 * (value[i+2] - '0') + + (value[i+3] - '0')); + else + result.setMillisecond (0); + + result_tm.tm_isdst =3D -1; + return result; } }; @@ -266,13 +389,16 @@ throw( FieldConvertError& ) { char result[ 9+4 ]; - int len =3D strftime( result, 9, "%H:%M:%S", value ); - if ( len !=3D 8 ) throw FieldConvertError(); + + integer_to_string_padded (result , 3, static_cast<const tm*>(value)= ->tm_hour, 2, '0'); result[2] =3D ':'; + integer_to_string_padded (result + 3, 3, static_cast<const tm*>(value)= ->tm_min, 2, '0'); result[5] =3D ':'; + integer_to_string_padded (result + 6, 3, static_cast<const tm*>(value)= ->tm_sec, 2, '0'); if(true=3D=3DshowMilliseconds) { - len =3D sprintf(result+8,".%03d",value.getMillisecond()); - if ( len !=3D 4) throw FieldConvertError(); + result[8] =3D '.'; + if (integer_to_string_padded (result + 9, 4, value.getMillisecond(),= 3, '0') !=3D result + 9) + throw FieldConvertError(); } return result; @@ -282,19 +408,52 @@ throw( FieldConvertError& ) { UtcTimeOnly result; - const char* val =3D value.c_str(); - const char* len =3D strptime( val, "%H:%M:%S", result ); - if ( len - val !=3D 8 ) throw FieldConvertError(); - - // if we have milliseconds in the string, *len should be ".sss" - result.setMillisecond(0); - if(NULL !=3D len && strlen(len)=3D=3D4 && len[0] =3D=3D '.') - { - int ms =3D atoi(&len[1]); - if(ms < 0 || ms > 999) throw FieldConvertError(); - result.setMillisecond(ms); + bool have_milliseconds =3D false; + + switch (value.size()) { + case 12: have_milliseconds =3D true; + case 8: break; + default: throw FieldConvertError(); + } + + int i =3D 0; + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw FieldCo= nvertError(); + if (value[i++] !=3D ':') throw FieldConvertErr= or(); + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw FieldCo= nvertError(); + if (value[i++] !=3D ':') throw FieldConvertErr= or(); + for (int c=3D0; c<2; ++c) if (!std::isdigit(value[i++])) throw FieldCo= nvertError(); + if (have_milliseconds) { + // ++i instead of i++ skips the '.' separator + for (int c=3D0; c<3; ++c) if (!std::isdigit(value[++i])) throw Field= ConvertError(); } + tm & result_tm =3D *static_cast<tm*>(result); + + i =3D 0; + + result_tm.tm_hour =3D value[i++] - '0'; + result_tm.tm_hour =3D 10 * result_tm.tm_hour + value[i++] - '0'; + if (23 < result_tm.tm_hour) throw FieldConvertError(); // No check for= >=3D 0 as no '-' are converted here + ++i; // skip ':' + + result_tm.tm_min =3D value[i++] - '0'; + result_tm.tm_min =3D 10 * result_tm.tm_min + value[i++] - '0'; + if (59 < result_tm.tm_min) throw FieldConvertError(); // No check for = >=3D 0 as no '-' are converted here + ++i; // skip ':' + + result_tm.tm_sec =3D value[i++] - '0'; + result_tm.tm_sec =3D 10 * result_tm.tm_sec + value[i++] - '0'; + if (60 < result_tm.tm_sec) throw FieldConvertError(); // No check for = >=3D 0 as no '-' are converted here + + if (have_milliseconds) + result.setMillisecond (100 * (value[i+1] - '0') + + 10 * (value[i+2] - '0') + + (value[i+3] - '0')); + else + result.setMillisecond (0); + + result_tm.tm_isdst =3D -1; + return result; } }; @@ -306,8 +465,9 @@ throw( FieldConvertError& ) { char result[ 9 ]; - int len =3D strftime( result, 9, "%Y%m%d", value ); - if ( len !=3D 8 ) throw FieldConvertError(); + integer_to_string_padded (result , 5, static_cast<const tm*>(value= )->tm_year + 1900, 4, '0'); + integer_to_string_padded (result + 4, 3, static_cast<const tm*>(value= )->tm_mon + 1, 2, '0'); + integer_to_string_padded (result + 6, 3, static_cast<const tm*>(value= )->tm_mday, 2, '0'); return result; } @@ -315,9 +475,34 @@ throw( FieldConvertError& ) { UtcDate result; - const char* val =3D value.c_str(); - const char* len =3D strptime( val, "%Y%m%d", result ); - if ( len - val !=3D 8 ) throw FieldConvertError(); + + if (value.size() !=3D 8) throw FieldConvertError(); + + int i =3D 0; + for (int c=3D0; c<8; ++c) if (!std::isdigit(value[i++])) throw FieldCo= nvertError(); + + tm & result_tm =3D *static_cast<tm*>(result); + + i =3D 0; + + result_tm.tm_year =3D value[i++] - '0'; + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; + result_tm.tm_year =3D 10 * result_tm.tm_year + value[i++] - '0'; + result_tm.tm_year -=3D 1900; + + result_tm.tm_mon =3D value[i++] - '0'; + result_tm.tm_mon =3D 10 * result_tm.tm_mon + value[i++] - '0'; + if (result_tm.tm_mon < 1 || 12 < result_tm.tm_mon) throw FieldConvertE= rror(); + --result_tm.tm_mon; + + result_tm.tm_mday =3D value[i++] - '0'; + result_tm.tm_mday =3D 10 * result_tm.tm_mday + value[i++] - '0'; + if (result_tm.tm_mday < 1 || 31 < result_tm.tm_mday) throw FieldConver= tError(); + ++i; // skip '-' + + result_tm.tm_isdst =3D -1; + return result; } }; <font face=3D"Times New Roman" size=3D"3"> <p>------------------------------------------------------------------------= ------</p> <p> This email is intended only for the use of the individual(s) to whom it= is addressed and may be privileged and confidential. Unauthorised use or d= isclosure is prohibited. If you receive this e-mail in error, please advise= immediately and delete the original message. This message may have been al= tered without your or our knowledge and the sender does not accept any liab= ility for any errors or omissions in the message.</p> <p>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D</p> </font> |
From: Oren M. <or...@qu...> - 2004-08-10 18:09:57
|
Hello everyone, First, we are working on putting out a new release of QuickFIX very soon. It's a pretty exciting one with a long anticipated feature and amazing performance improvements. However right now I have another announcement. A couple of the things that I've found missing in the FIX and trading communities are an organized up-to-date knowledge base, and an active self-run FIX community outside of the FPL. In addition to this, we have been struggling with organizing our own QuickFIX community. The mailing lists are useful, but not well organized, and not a great place to work out a lot of concepts in detail. In order to address these issues, we are introducing WikiFIX, which as it sounds, is a Wiki dedicated to FIX and electronic trading. For those not familiar with Wiki, it is essentially a website where everyone can contribute to the content. Read more about it here: http://en.wikipedia.org/wiki/Wiki You can access WikiFIX either from http://www.wikifix.org, or http://www.quickfixengine.org/wikifix. Both addresses go to the same place. The starting page for QuickFIX specific information is at http://www.wikifix.org/index.php?QuickFix. Here, everyone can contribute to the FAQ, report issues, resolutions, patches, or anything else that we haven't thought of yet. Like any Wiki, it is dependent on all of us to make the most out of it. Right now I am only announcing this to the QuickFIX community, but I hope to broaden the audience in time. We intend for the Wiki to be vendor neutral. Hopefully it will allow various engines vendors, counter-parties, and all the rest of us communicating in an open, self organizing, and continuously updating resource. --oren |
From: Oren M. <or...@qu...> - 2004-08-10 14:29:27
|
Hello everyone, First, we are working on putting out a new release of QuickFIX very soon. It's a pretty exciting one with a long anticipated feature and amazing performance improvements. However right now I have another announcement. A couple of the things that I've found missing in the FIX and trading communities are an organized up-to-date knowledge base, and an active self-run FIX community outside of the FPL. In addition to this, we have been struggling with organizing our own QuickFIX community. The mailing lists are useful, but not well organized, and not a great place to work out a lot of concepts in detail. In order to address these issues, we are introducing WikiFIX, which as it sounds, is a Wiki dedicated to FIX and electronic trading. For those not familiar with Wiki, it is essentially a website where everyone can contribute to the content. Read more about it here: http://en.wikipedia.org/wiki/Wiki You can access WikiFIX either from http://www.wikifix.org, or http://www.quickfixengine.org/wikifix. Both addresses go to the same place. The starting page for QuickFIX specific information is at http://www.wikifix.org/index.php?QuickFix. Here, everyone can contribute to the FAQ, report issues, resolutions, patches, or anything else that we haven't thought of yet. Like any Wiki, it is dependent on all of us to make the most out of it. Right now I am only announcing this to the QuickFIX community, but I hope to broaden the audience in time. We intend for the Wiki to be vendor neutral. Hopefully it will allow various engines vendors, counter-parties, and all the rest of us communicating in an open, self organizing, and continuously updating resource. --oren |
From: Oren M. <or...@qu...> - 2004-08-10 00:13:31
|
You can't really do this because you can have multiple versions running=20= with the same TargetCompID. Also you can have two sessions with the=20 same TargetCompID if the SenderCompIDs are different. This is why all=20= of these values are necessary to identify a session. If you know your=20= TargetCompIDs are completely unique, you can create a map of=20 TargetCompIDs to SessionIDs that are passed to you in the onCreate=20 method. Then you can do this lookup yourself on your map. --oren On Aug 9, 2004, at 2:17 PM, Jiaming Shu wrote: > HI, > =A0 > I am new to this=A0quickFIX program. One thing I was looking for is = how=20 > to get a session's FIX version if the TargetCompID is available. I did=20= > not find a way in the doc to get this information by taking=20 > TargetCompID as parameter. Nor did I find anything related to this=20 > question on your email achives. > =A0 > Thanks in advance for your reply. > =A0 > Thanks, > =A0 > > Do you Yahoo!? > New and Improved Yahoo! Mail - 100MB free storage!= |