Skip to content

Optimize some constant string operations#703

Merged
chambart merged 6 commits intoocaml:trunkfrom
chambart:optimize_constant_strings
Jul 28, 2016
Merged

Optimize some constant string operations#703
chambart merged 6 commits intoocaml:trunkfrom
chambart:optimize_constant_strings

Conversation

@chambart
Copy link
Copy Markdown
Contributor

Since #687 some constant string operations can be simplified.
This currently propose eliminating string switch when the argument is a constant string ( @yallop thinks that this can matter for Ctypes ). This also tweaks a few things to improve char lookup.

Notice that this kind of change makes using Bytes.unsafe_to_string more unsafe.

I can add various other cases (Pervasives.(^), String.equal, String.compare, int_of_string, string_of_int, ...) if someone consider that useful .

@yallop
Copy link
Copy Markdown
Member

yallop commented Jul 21, 2016

Thanks, @chambart. This seems to help quite a bit.

Here's a simple test case, a Ctypes binding for a couple of C functions:

module F(F: Cstubs.FOREIGN) =
struct
  open F
  let succ = foreign "succ" (int @-> returning int)
  let sqrt = foreign "sqrt" (double @-> returning double)
end

From this code, Ctypes generates some C stubs and a module with a foreign function that can be passed to F to link to the stubs. Here's the generated module, somewhat simplified:

external t1_succ : int -> int = "t1_succ" 
external t2_sqrt : float -> float = "t2_sqrt" 

let foreign : type a b. string -> (a -> b) fn -> (a -> b) =
  fun name t -> match t, name with
| Function (Primitive Double, Returns (Primitive Double)), "sqrt" -> t2_sqrt
| Function (Primitive Int, Returns (Primitive Int)), "succ" -> t1_succ
| _, s ->  Printf.ksprintf failwith "No match for %s" s

and here's the code to link the binding and the generated module:

include F(Generated)

Since the values passed to foreign (e.g. "succ" and (int @-> returning int)) are statically visible it would be nice if the application could be optimized away at compile time. But the current release (4.03.0+flambda) doesn't optimize the string match in the generated foreign function, and so the code generated for the final line (the functor application) is quite large and complex:

initialize_symbol
  (Applied.camlApplied__include_49 0
     (let
       (apply_arg/82 Binding.camlBinding__apply_arg_53
        succ/84
          *(catch
             (stringswitch apply_arg/82
              case "succ":
               (let
                 (project_closure_anon-fn/111
                    Generated.camlGenerated__anon-fn_101_closure)
                 project_closure_anon-fn/111)
              default: (exit 1))
            with (1)
             (let
               (apply_arg/112 Generated.camlGenerated__Pmakeblock_171
                Pfield/113 Pervasives.camlPervasives__failwith_285_closure
                Pfield/114 Printf.camlPrintf__ksprintf_179_closure
                full_apply/115
                  *(apply*[Printf.ksprintf/179] Pfield/114 Pfield/113
                     apply_arg/112))
               (apply full_apply/115 apply_arg/82)))
...
initialize_symbol
  (Applied.camlApplied__Pmakeblock_arg_47 0
     (let
       (include/58 Applied.camlApplied__include_49.(0)
        Pmakeblock_arg/46 (field 0 include/58))
       Pmakeblock_arg/46))
...
initialize_symbol
  (Applied.camlApplied 0
     (let
       (block_symbol_get_field_0/2 Applied.camlApplied__Pmakeblock_arg_47.(0))
       block_symbol_get_field_0/2)
...

(and this is just for the succ binding! There's similar code generated for sqrt.)

However, the compiler built from this PR optimizes absolutely everything away, including the entire call to foreign, and the pattern match. Here's the generated code in its entirety:

let_symbol
  (Applied.camlApplied (Block (tag 0, 
     Generated.camlGenerated__anon-fn[generated.ml:20,2--13]_89_closure
     Generated.camlGenerated__anon-fn[generated.ml:18,2--13]_111_closure)))

(this is for both succ and sqrt). In other words, the functor, the function applications, the values (int @-> returning int etc.) describing the types of the bound functions, the pattern matching, all disappear from the generated code; it's as if I'd written the simplest possible code in the first place:

external t1_succ : int -> int = "t1_succ" 
external t2_sqrt : float -> float = "t2_sqrt" 

let succ = t1_succ
let sqrt = t2_sqrt

So for simple cases, at least, this PR looks like a significant improvement for Ctypes.

@alainfrisch
Copy link
Copy Markdown
Contributor

#687 introduces a new configure-time option. I assume the new optimizations should only be triggered when the system has been configured in this mode.

@bobzhang
Copy link
Copy Markdown
Member

this might be helpful #596

@chambart
Copy link
Copy Markdown
Contributor Author

@yallop Thanks for testing.

@alainfrisch this is enabled by your change in Closure_conversion https://github.com/ocaml/ocaml/pull/687/files#diff-cf66b45f8983f3e9e6a793b9d796de3fL129

@bobzhang Not really, this only applies to constant strings that we already know to be immutable here. I don't intend to optimize any complex pattern (when everything is not a constant), so there is no need for more information. If you can produce some interesting use case for some slightly more complex optimization on strings, I would be happy to reconsider that.

@chambart chambart force-pushed the optimize_constant_strings branch 2 times, most recently from 01f8328 to 4482f19 Compare July 21, 2016 15:48
@chambart chambart force-pushed the optimize_constant_strings branch 2 times, most recently from db19a98 to 158dc94 Compare July 28, 2016 17:33
@chambart chambart force-pushed the optimize_constant_strings branch from 158dc94 to 3b6a802 Compare July 28, 2016 17:36
@chambart chambart merged commit 1294a6d into ocaml:trunk Jul 28, 2016
camlspotter pushed a commit to camlspotter/ocaml that referenced this pull request Oct 17, 2017
stedolan pushed a commit to stedolan/ocaml that referenced this pull request Sep 21, 2022
stedolan pushed a commit to stedolan/ocaml that referenced this pull request Sep 21, 2022
ce76e02 flambda-backend: Bugfix for type_application (ocaml#746)
44f3afb flambda-backend: PR580 for main branch (ocaml#743)
b851eaa flambda-backend: Backport first part of ocaml/ocaml PR10498 (ocaml#737)
fafb4bd flambda-backend: Fix return mode for eta-expanded function in type_argument (ocaml#735)
c31f6c3 flambda-backend: Fix treatment of functions called [@nontail] (ocaml#725)
847781e flambda-backend: Fix build_upstream post-PR703 (ocaml#712)
bfcbbf8 flambda-backend: Extend Pblock value kind to handle variants (ocaml#703)
b2cab95 flambda-backend: Merge ocaml-jst
a6d6e0e flambda-backend: Merge ocaml-jst
88a4f63 flambda-backend: Use Pmakearray for immutable arrays (ocaml#699)
eeaa44b flambda-backend: Install an ocamldoc binary (ocaml#695)
48d322b flambda-backend: Ensure that GC is not invoked from bounds check failures (ocaml#681)
4370fa1 flambda-backend: Review changes of term directory (ocaml#602)
65a4566 flambda-backend: Add code coverage using bisect_ppx (ocaml#352)
63ab65f flambda-backend: Bugfix for primitive inclusion (ocaml#662)
7e3e0c8 flambda-backend: Fix inclusion checks for primitives (ocaml#661)
96c68f9 flambda-backend: Speed up linking by changing cmxa format (ocaml#607)
1829150 flambda-backend: Bugfix for Translmod.all_idents (ocaml#659)

git-subtree-dir: ocaml
git-subtree-split: ce76e02
sadiqj pushed a commit to sadiqj/ocaml that referenced this pull request Feb 21, 2023
EmileTrotignon pushed a commit to EmileTrotignon/ocaml that referenced this pull request Jan 12, 2024
* Ood: move sorting

* Ood: sort reverse instead of rev after sort

Co-authored-by: Cuihtlauac ALVARADO <cuihtmlauac@tarides.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants