diff options
Diffstat (limited to 'tex/context/base/node-nut.lua')
-rw-r--r-- | tex/context/base/node-nut.lua | 650 |
1 files changed, 0 insertions, 650 deletions
diff --git a/tex/context/base/node-nut.lua b/tex/context/base/node-nut.lua deleted file mode 100644 index 4732b09eb..000000000 --- a/tex/context/base/node-nut.lua +++ /dev/null @@ -1,650 +0,0 @@ -if not modules then modules = { } end modules ['node-met'] = { - version = 1.001, - comment = "companion to node-ini.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- Here starts some more experimental code that Luigi and I use in a next stage of --- exploring and testing potential speedups in the engines. This code is not meant --- for users and can change (or be removed) any moment. During the experiments I'll --- do my best to keep the code as fast as possible by using two codebases. See --- about-fast.pdf for some more info about impacts. Although key based access has --- more charm, function based is somewhat faster and has more potential for future --- speedups. - --- This next iteration is flagged direct because we avoid user data which has a price --- in allocation and metatable tagging. Although in this stage we pass numbers around --- future versions might use light user data, so never depend on what direct function --- return. Using the direct approach had some speed advantages but you loose the key --- based access. The speed gain is only measurable in cases with lots of access. For --- instance when typesettign arabic with advanced fonts, we're talking of many millions --- of function calls and there we can get a 30\% or more speedup. On average complex --- \CONTEXT\ runs the gain can be 10\% to 15\% percent. Because mixing the two models --- (here we call then nodes and nuts) is not possible you need to cast either way which --- has a penalty. Also, error messages in nuts mode are less clear and \LUATEX\ will --- often simply abort when you make mistakes of mix the models. So, development (at least --- in \CONTEXT) can be done in node mode and not in nuts mode. Only robust code will --- be turned nuts afterwards and quite likely not all code. The official \LUATEX\ api --- to nodes is userdata! --- --- Listening to 'lunatic soul' at the same time helped wrapping my mind around the mixed --- usage of both models. Just for the record: the potential of the direct approach only --- became clear after experimenting for weeks and partly adapting code. It is one of those --- (sub)projects where you afterwards wonder if it was worth the trouble, but users that --- rely on lots of complex functionality and font support will probably notice the speedup. --- --- luatex luajittex --- ------------- ----- -------------------- --------------------------------- --- name pages old new pct old new pct --- ------------- ----- -------------------- --------------------------------- --- fonts-mkiv 166 9.3 7.7/7.4 17.2 7.4 (37.5) 5.9/5.7 (55.6) 20.3 --- about 60 3.3 2.7/2.6 20.4 2.5 (39.5) 2.1 (57.0) 23.4 --- arabic-001 61 25.3 15.8 18.2 15.3 (46.7) 6.8 (54.7) 16.0 --- torture-001 300 21.4 11.4 24.2 13.9 (35.0) 6.3 (44.7) 22.2 --- --- so: --- --- - we run around 20% faster on documents of average complexity and gain more when --- dealing with scripts like arabic and such --- - luajittex benefits a bit more so a luajittex job can (in principle) now be much --- faster --- - if we reason backwards, and take luajittex as norm we get 1:2:3 on some jobs for --- luajittex direct:luatex direct:luatex normal i.e. we can be 3 times faster --- - keep in mind that these are tex/lua runs so the real gain at the lua end is much --- larger --- --- Because we can fake direct mode a little bit by using the fast getfield and setfield --- at the cost of wrapped getid and alike, we still are running quite ok. As we could gain --- some 5% with fast mode, we can sacrifice some on wrappers when we use a few fast core --- functions. This means that simulated direct mode runs font-mkiv in 9.1 seconds (we could --- get down to 8.7 seconds in fast mode) and that we can migrate slowely to direct mode. --- --- The following measurements are from 2013-07-05 after adapting some 47 files to nuts. Keep --- in mind that the old binary can fake a fast getfield and setfield but that the other --- getters are wrapped functions. The more we have, the slower it gets. --- --- fonts about arabic --- old mingw, indexed plus some functions : 8.9 3.2 20.3 --- old mingw, fake functions : 9.9 3.5 27.4 --- new mingw, node functions : 9.0 3.1 20.8 --- new mingw, indexed plus some functions : 8.6 3.1 19.6 --- new mingw, direct functions : 7.5 2.6 14.4 --- --- \starttext \dorecurse{1000}{test\page} \stoptext : --- --- luatex 560 pps --- luajittex 600 pps --- --- \setupbodyfont[pagella] --- --- \edef\zapf{\cldcontext{context(io.loaddata(resolvers.findfile("zapf.tex")))}} --- --- \starttext \dorecurse{1000}{\zapf\par} \stoptext --- --- luatex 3.9 sec / 54 pps --- luajittex 2.3 sec / 93 pps - -local nodes = nodes -local gonuts = nodes.gonuts -local direct = node.direct - -if type(direct) ~= "table" then - return -elseif gonuts then - statistics.register("running in nuts mode", function() return "yes" end) -else - statistics.register("running in nuts mode", function() return "no" end) - return -end - -local texget = tex.get - -local nodecodes = nodes.nodecodes -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist - -local nuts = nodes.nuts or { } -nodes.nuts = nuts - -nodes.is_node = direct.is_node or function() return true end -nodes.is_direct = direct.is_direct or function() return false end -nodes.is_nut = nodes.is_direct - --- casters - -local tonode = direct.tonode or function(n) return n end -local tonut = direct.todirect or function(n) return n end - -nuts.tonode = tonode -nuts.tonut = tonut - -nodes.tonode = tonode -nodes.tonut = tonut - --- getters - -nuts.getfield = direct.getfield -nuts.getnext = direct.getnext -nuts.getprev = direct.getprev -nuts.getid = direct.getid -nuts.getattr = direct.getfield -nuts.getchar = direct.getchar -nuts.getfont = direct.getfont -nuts.getsubtype = direct.getsubtype -nuts.getlist = direct.getlist -- only hlist and vlist ! -nuts.getleader = direct.getleader - --- local dgf = direct.getfield function nuts.getlist(n) return dgf(n,"list") end - --- setters - -nuts.setfield = direct.setfield -nuts.setattr = direct.setfield - -nuts.getbox = direct.getbox -nuts.setbox = direct.setbox -nuts.getskip = direct.getskip or function(s) return tonut(texget(s)) end - --- helpers - -nuts.tostring = direct.tostring -nuts.copy = direct.copy -nuts.copy_list = direct.copy_list -nuts.delete = direct.delete -nuts.dimensions = direct.dimensions -nuts.end_of_math = direct.end_of_math -nuts.flush_list = direct.flush_list -nuts.flush_node = direct.flush_node -nuts.free = direct.free -nuts.insert_after = direct.insert_after -nuts.insert_before = direct.insert_before -nuts.hpack = direct.hpack -nuts.new = direct.new -nuts.tail = direct.tail -nuts.traverse = direct.traverse -nuts.traverse_id = direct.traverse_id -nuts.slide = direct.slide -nuts.writable_spec = direct.writable_spec -nuts.vpack = direct.vpack -nuts.is_node = direct.is_node -nuts.is_direct = direct.is_direct -nuts.is_nut = direct.is_direct -nuts.first_glyph = direct.first_glyph -nuts.first_character = direct.first_character -nuts.has_glyph = direct.has_glyph or direct.first_glyph - -nuts.current_attr = direct.current_attr -nuts.do_ligature_n = direct.do_ligature_n -nuts.has_field = direct.has_field -nuts.last_node = direct.last_node -nuts.usedlist = direct.usedlist -nuts.protrusion_skippable = direct.protrusion_skippable -nuts.write = direct.write - -nuts.has_attribute = direct.has_attribute -nuts.set_attribute = direct.set_attribute -nuts.unset_attribute = direct.unset_attribute - -nuts.protect_glyphs = direct.protect_glyphs -nuts.unprotect_glyphs = direct.unprotect_glyphs - --- placeholders - -if not direct.kerning then - - local n_kerning = node.kerning - - function nuts.kerning(head) - return tonode(n_kerning(tonut(head))) - end - -end - -if not direct.ligaturing then - - local n_ligaturing = node.ligaturing - - function nuts.ligaturing(head) - return tonode(n_ligaturing(tonut(head))) - end - -end - -if not direct.mlist_to_hlist then - - local n_mlist_to_hlist = node.mlist_to_hlist - - function nuts.mlist_to_hlist(head) - return tonode(n_mlist_to_hlist(tonut(head))) - end - -end - --- - -local d_remove_node = direct.remove -local d_free_node = direct.free -local d_getfield = direct.getfield -local d_setfield = direct.setfield -local d_getnext = direct.getnext -local d_getprev = direct.getprev -local d_getid = direct.getid -local d_getlist = direct.getlist -local d_find_tail = direct.tail -local d_insert_after = direct.insert_after -local d_insert_before = direct.insert_before -local d_slide = direct.slide -local d_copy_node = direct.copy -local d_traverse = direct.traverse - -local function remove(head,current,free_too) - local t = current - head, current = d_remove_node(head,current) - if not t then - -- forget about it - elseif free_too then - d_free_node(t) - t = nil - else - d_setfield(t,"next",nil) -- not that much needed (slows down unless we check the source on this) - d_setfield(t,"prev",nil) -- not that much needed (slows down unless we check the source on this) - end - return head, current, t -end - --- bad: we can have prev's being glue_spec - --- local function remove(head,current,free_too) -- d_remove_node does a slide which can fail --- local prev = d_getprev(current) -- weird --- local next = d_getnext(current) --- if next then --- -- print("!!!!!!!! prev is gluespec", --- -- nodes.nodecodes[d_getid(current)], --- -- nodes.nodecodes[d_getid(next)], --- -- nodes.nodecodes[d_getid(prev)]) --- d_setfield(prev,"next",next) --- d_setfield(next,"prev",prev) --- else --- d_setfield(prev,"next",nil) --- end --- if free_too then --- d_free_node(current) --- current = nil --- else --- d_setfield(current,"next",nil) -- use this fact ! --- d_setfield(current,"prev",nil) -- use this fact ! --- end --- if head == current then --- return next, next, current --- else --- return head, next, current --- end --- end - -nuts.remove = remove - -function nuts.delete(head,current) - return remove(head,current,true) -end - -function nuts.replace(head,current,new) -- no head returned if false - if not new then - head, current, new = false, head, current - end - local prev = d_getprev(current) - local next = d_getnext(current) - if next then - d_setfield(new,"next",next) - d_setfield(next,"prev",new) - end - if prev then - d_setfield(new,"prev",prev) - d_setfield(prev,"next",new) - end - if head then - if head == current then - head = new - end - d_free_node(current) - return head, new - else - d_free_node(current) - return new - end -end - -local function count(stack,flat) - local n = 0 - while stack do - local id = d_getid(stack) - if not flat and id == hlist_code or id == vlist_code then - local list = d_getlist(stack) - if list then - n = n + 1 + count(list) -- self counts too - else - n = n + 1 - end - else - n = n + 1 - end - stack = d_getnext(stack) - end - return n -end - -nuts.count = count - -function nuts.append(head,current,...) - for i=1,select("#",...) do - head, current = d_insert_after(head,current,(select(i,...))) - end - return head, current -end - -function nuts.prepend(head,current,...) - for i=1,select("#",...) do - head, current = d_insert_before(head,current,(select(i,...))) - end - return head, current -end - -function nuts.linked(...) - local head, last - for i=1,select("#",...) do - local next = select(i,...) - if next then - if head then - d_setfield(last,"next",next) - d_setfield(next,"prev",last) - else - head = next - end - last = d_find_tail(next) -- we could skip the last one - end - end - return head -end - -function nuts.concat(list) -- consider tail instead of slide - local head, tail - for i=1,#list do - local li = list[i] - if li then - if head then - d_setfield(tail,"next",li) - d_setfield(li,"prev",tail) - else - head = li - end - tail = d_slide(li) - end - end - return head, tail -end - -function nuts.writable_spec(n) -- not pool - local spec = d_getfield(n,"spec") - if not spec then - spec = d_copy_node(glue_spec) - d_setfield(n,"spec",spec) - elseif not d_getfield(spec,"writable") then - spec = d_copy_node(spec) - d_setfield(n,"spec",spec) - end - return spec -end - -function nuts.reference(n) - return n or "<none>" -end - --- quick and dirty tracing of nuts - --- for k, v in next, nuts do --- if string.find(k,"box") then --- nuts[k] = function(...) print(k,...) return v(...) end --- end --- end - -function nodes.vianuts (f) return function(n,...) return tonode(f(tonut (n),...)) end end -function nodes.vianodes(f) return function(n,...) return tonut (f(tonode(n),...)) end end - -nuts.vianuts = nodes.vianuts -nuts.vianodes = nodes.vianodes - --- for k, v in next, nuts do --- if type(v) == "function" then --- if not string.find(k,"^[sg]et") and not string.find(k,"^to") then --- local f = v --- nuts[k] = function(...) print("d",k,...) return f(...) end --- end --- end --- end - --- for k, v in next, nodes do --- if type(v) == "function" then --- if not string.find(k,"^[sg]et") and not string.find(k,"^to") then --- local f = v --- nodes[k] = function(...) print("n",k,...) return f(...) end --- end --- end --- end - --- function nodes.insert_before(h,c,n) --- if c then --- if c == h then --- n_setfield(n,"next",h) --- n_setfield(n,"prev",nil) --- n_setfield(h,"prev",n) --- else --- local cp = n_getprev(c) --- n_setfield(n,"next",c) --- n_setfield(n,"prev",cp) --- if cp then --- n_setfield(cp,"next",n) --- end --- n_setfield(c,"prev",n) --- return h, n --- end --- end --- return n, n --- end - --- function nodes.insert_after(h,c,n) --- if c then --- local cn = n_getnext(c) --- if cn then --- n_setfield(n,"next",cn) --- n_setfield(cn,"prev",n) --- else --- n_setfield(n,"next",nil) --- end --- n_setfield(c,"next",n) --- n_setfield(n,"prev",c) --- return h, n --- end --- return n, n --- end - -function nodes.insert_list_after(h,c,n) - local t = n_tail(n) - if c then - local cn = n_getnext(c) - if cn then - n_setfield(t,"next",cn) - n_setfield(cn,"prev",t) - else - n_setfield(t,"next",nil) - end - n_setfield(c,"next",n) - n_setfield(n,"prev",c) - return h, n - end - return n, t -end - --- function nuts.insert_before(h,c,n) --- if c then --- if c == h then --- d_setfield(n,"next",h) --- d_setfield(n,"prev",nil) --- d_setfield(h,"prev",n) --- else --- local cp = d_getprev(c) --- d_setfield(n,"next",c) --- d_setfield(n,"prev",cp) --- if cp then --- d_setfield(cp,"next",n) --- end --- d_setfield(c,"prev",n) --- return h, n --- end --- end --- return n, n --- end - --- function nuts.insert_after(h,c,n) --- if c then --- local cn = d_getnext(c) --- if cn then --- d_setfield(n,"next",cn) --- d_setfield(cn,"prev",n) --- else --- d_setfield(n,"next",nil) --- end --- d_setfield(c,"next",n) --- d_setfield(n,"prev",c) --- return h, n --- end --- return n, n --- end - -function nuts.insert_list_after(h,c,n) - local t = d_tail(n) - if c then - local cn = d_getnext(c) - if cn then - d_setfield(t,"next",cn) - d_setfield(cn,"prev",t) - else - d_setfield(t,"next",nil) - end - d_setfield(c,"next",n) - d_setfield(n,"prev",c) - return h, n - end - return n, t -end - --- test code only - --- collectranges and mix - -local report = logs.reporter("sliding") - -local function message(detail,head,current,previous) - report("error: %s, current: %s:%s, previous: %s:%s, list: %s, text: %s", - detail, - nodecodes[d_getid(current)], - current, - nodecodes[d_getid(previous)], - previous, - nodes.idstostring(head), - nodes.listtoutf(head) - ) - utilities.debugger.showtraceback(report) -end - -local function warn() - report() - report("warning: the slide tracer is enabled") - report() - warn = false -end - -local function tracedslide(head) - if head then - if warn then - warn() - end - local next = d_getnext(head) - if next then - local prev = head - for n in d_traverse(next) do - local p = d_getprev(n) - if not p then - message("unset",head,n,prev) - -- break - elseif p ~= prev then - message("wrong",head,n,prev) - -- break - end - prev = n - end - end - return d_slide(head) - end -end - -local function nestedtracedslide(head,level) -- no sliding ! - if head then - if warn then - warn() - end - local id = d_getid(head) - local next = d_getnext(head) - if next then - report("%whead:%s",level or 0,nodecodes[id]) - local prev = head - for n in d_traverse(next) do - local p = d_getprev(n) - if not p then - message("unset",head,n,prev) - -- break - elseif p ~= prev then - message("wrong",head,n,prev) - -- break - end - prev = n - local id = d_getid(n) - if id == hlist_code or id == vlist_code then - nestedtracedslide(d_getlist(n),(level or 0) + 1) - end - end - elseif id == hlist_code or id == vlist_code then - report("%wlist:%s",level or 0,nodecodes[id]) - nestedtracedslide(d_getlist(head),(level or 0) + 1) - end - -- return d_slide(head) - end -end - -local function untracedslide(head) - if head then - if warn then - warn() - end - local next = d_getnext(head) - if next then - local prev = head - for n in d_traverse(next) do - local p = d_getprev(n) - if not p then - return "unset", d_getid(n) - elseif p ~= prev then - return "wrong", d_getid(n) - end - prev = n - end - end - return d_slide(head) - end -end - -nuts.tracedslide = tracedslide -nuts.untracedslide = untracedslide -nuts.nestedtracedslide = nestedtracedslide - --- nuts.slide = tracedslide |