smlfut(1)
π Name π
Okay so this is <pink>smlfut(1)</pink> from the General Commands Manual, bestie β and <pink>smlfut</pink> means call Futhark from Standard ML. That's the whole vibe. π
β¨ Synopsis β¨
smlfut [options] MANIFEST.json
π Description π
<pink>smlfut</pink> lets SML programs invoke Futhark programs through Futhark's C API, by generating appropriate wrapper code, which is then compiled as normal with an SML compiler. It's literally the glue between your SML and your Futhark, no cap. π¦
π οΈ Options π οΈ
--mono-arraysβ Equivalent to--target=mlton-mono.--poly-arraysβ Equivalent to--target=mlton-poly.--output-directory=NAMEβ Write output files to this directory.--signature-name=NAMEβ Use this name for the SML signature. Defaults to the uppercased basename of the manifest file.--structure-name=NAMEβ Use this name for the SML structure. Defaults to the basename of the manifest file.--target=TARGETβ Target this SML compiler. Must be one ofmlkit,mlton-poly, ormlton-mono(the default).-V,--versionβ Print version information.
π§ Usage π§
First compile a Futhark program foo.fut with futhark(1) using one of the C backends, then pass the generated JSON manifest file foo.json to smlfut. This will produce three files: foo.sig, foo.sml, and foo.smlfut.c. The first two files contain definitions of SML signatures and structures, while the last contains C code. The name of the structure will be taken from the file basename (in this case 'foo') and the signature name will be the structure name in all caps ('FOO'). The generated SML files can be passed to the SML compiler, and the final executable must be linked with foo.smlfut.c, and of course the C file generated by the Futhark compiler itself.
The generated interface directly exposes the C API, so it is low level. The only concession is that the C error codes are turned into SML exceptions.
The generated signatures are designed to be human readable and should be mostly straightforward. The general principle is that you construct a context by passing a configuration record. The context maintains Futhark state and is passed to entry points and various other functions.
Different context objects are not interchangeable, despite having the same type, and Futhark values obtained via one context may not be passed to another. Like, do not mix those contexts, bestie. π
π Top level signature π
The generated structure implements the following signature (here using the name FUTHARK, but this is taken from the program file name or the --signature-name option).
signature FUTHARK =
sig
val backend : string
val version : string
type ctx
exception Error of string
exception Free
type cfg = { logging:bool,
, debugging:bool
, profiling:bool
, cache:string option
, tuning: (string * int) list
(* Possibly more *)
}
structure Config : sig
(* See below *)
end
structure Context : sig
(* See below *)
end
(* Array specs... *)
structure Opaque : sig
(* Opaque type specs... *)
end
structure Entry : sig
(* Entry points... *)
end
end
πΈ Description πΈ
backendβ The Futhark compiler backend used to compile the program.versionβ The Futhark compiler version used to compile the program.exception Errorβ Raised when Futhark execution fails. The string is the error message reported by Futhark.exception Freeβ Raised when an attempt is made to use an object that has been freed.type ctxβ Contains Futhark runtime state.type cfgβ Configuration record used to create the context. Depending on the backend, this record may have more fields.structure Config/Context/Opaque/Entryβ See below.
π οΈ The Config Structure π οΈ
Facilities for easily constructing or modifying configuration records. In particular, the structure exposes a setter for each field in the configuration record, as SML's built-in facilities for updating records are rather cumbersome. It's giving "setter slay." π
structure Config : sig
val default : cfg
val logging : bool -> cfg -> cfg
val debugging : bool -> cfg -> cfg
val profiling : bool -> cfg -> cfg
val cache : string option -> cfg -> cfg
val tuning : (string * int) list -> cfg -> cfg
(* Possibly more *)
end
π The Context Structure π
The context is essentially the Futhark runtime state. Main character energy, honestly. π
structure Context : sig
val new : cfg -> ctx
val free : ctx -> unit
val sync : ctx -> unit
val report : ctx -> string
val pauseProfiling : ctx -> unit
val unpauseProfiling : ctx -> unit
val clearCaches : ctx -> unit
end
π Description π
newβ Create a context from a configuration. May be quite slow β don't call it too often. May throwErrorif initialisation of the Futhark context fails, or if an invalid tuning parameter is provided in the configuration.freeβ Free a context. It may not be used again. There is no guarantee that this frees any Futhark values (e.g. arrays) associated with the context. To avoid memory leaks, make sure to free all values before freeing the context.syncβ Wait for all asynchronous operations to finish. Depending on the Futhark backend, entry points may execute asynchronously, and errors may not be reported until the next function call. UseContext.syncto ensure all errors have been detected.reportβ Retrieve (and reset) current profiling information. Contains much more interesting information if the configuration had itsprofilingfield set totrue.pauseProfilingβ Temporarily suspend the collection of profiling information. Has no effect if profiling was not enabled in the configuration, or if profiling is already paused.unpauseProfilingβ Resume the collection of profiling information. Has no effect if profiling was not enabled in the configuration, or if profiling is not currently paused.clearCachesβ Release any context-internal caches and buffers that may otherwise use computer resources. Will not invalidate any values or ongoing computation.
π¦ The Entry Structure π¦
This structure contains an SML function for each corresponding Futhark entry point. They all have the type
val foo : ctx -> args -> result
where args and result may be tuples. Futhark's scalar types are mapped directly to the corresponding SML types, e.g. f64 to Real64. Each non-primitive type is represented by an appropriate abstract type, which presents an interface to the underlying Futhark value, as discussed below. While execution of an entry point can in principle be asynchronous, this is not semantically visible. The result(s) returned by an entry point can be used immediately. You only need to call Context.sync if you wish to check for errors.
π Array Structures π
Depending on the target compiler, each Futhark array type is represented by a structure implementing one of the signatures below. The mlton-poly target uses polymorphic arrays, while all other targets use monomorphic arrays.
signature FUTHARK_MONO_ARRAY =
sig
type array
type ctx
type shape
type index
type raw
structure Array : MONO_ARRAY
structure Slice : MONO_ARRAY_SLICE
val new: ctx -> Slice.slice -> shape -> array
val free: array -> unit
val shape: array -> shape
val index: array -> index -> Array.elem
val values: array -> native.array
val values_into: array -> Slice.slice -> unit
val new_raw: ctx -> raw -> shape -> array
val values_raw: array -> raw
end
signature FUTHARK_POLY_ARRAY =
sig
type array
type ctx
type shape
type index
type elem
type raw
val new: ctx -> elem ArraySlice.slice -> shape -> array
val free: array -> unit
val shape: array -> shape
val index: array -> index -> elem
val values: array -> elem Array.array
val values_into: array -> elem ArraySlice.slice -> unit
val new_raw: ctx -> raw -> shape -> array
val values_raw: array -> raw
end
The name of an array structure is similar to the naming of monomorphic arrays in the SML basis library, e.g., Int32Array1 for []i32 and Real32Array32 for [][]f32.
β Description β
type arrayβ The abstract array type.type ctxβ The Futhark context type. Each array structure refines this to be identical to thetype ctxtype of the top level structure.type shapeβ A type for the shape of the array. This isintfor single dimensional arrays, and otherwise a tuple of integers.type indexβ A type for valid indexes into the array. This is identical toshapeand is only present to make the types more readable.indexβ Read a single element from the array. RaisesSubscripton out of bounds.newβ Construct a Futhark array from an SML array slice. RaisesSizeif the length of the array slice is not equal to the product of the provided shape.rawβ The type of the raw underlying pointer corresponding to the array memory.freeβ Frees the array. Do not use it again. If you do not manually call this function when you are done with the array, then you leak memory.valuesβ Synchronously copy the Futhark array into a freshly constructed SML array.values_intoβ Synchronously copy the Futhark array into an existing SML array slice. RaisesSizeif the length of the slice is not equal to the product of the array shape.new_rawβ Construct an array from a raw pointer, without copying. Futhark does not take ownership of this memory, and it must not be freed until Futhark no longer uses it.values_rawβ Retrieve a pointer to the raw data underlying this array.
π OPAQUE TYPES π
Each non-record opaque type is represented by a structure implementing the signature below.
signature FUTHARK_OPAQUE =
sig
type t
type ctx
val free : t -> unit
val store : t -> Word8Array.array
val restore : ctx -> Word8ArraySlice.slice -> t
end
π«§ Description π«§
freeβ frees the object. Do not use it again. If you donβt manually call this function when youβre done with the object, then memory will be leaked. fr fr, leak city bestie πstoreβ serialise the value to a byte array. clean, simple, iconic β¨restoreβ restore a value from its serialised representation.
Warning bestie: you should not pass untrusted data to restore, as this can result in memory corruption. like, do not do it π
The serialisation format is stable across compiler backends and recompilation, but not necessarily across different compiler versions β although in practice compatibility is broken very rarely. slay for stability π
π§Ύ RECORD TYPES π§Ύ
Each record type is represented by a structure implementing the signature below.
signature FUTHARK_RECORD =
sig
include FUTHARK_OPAQUE
type record
val values : t -> record
val new : ctx -> record -> t
end
Any struct that implements this signature will refine the record type such that the Futhark value can be constructed from an appropriate SML record. As a special case, a Futhark tuple (0-indexed) is associated with a properly 1-indexed SML tuple. iykyk π
Note that if you convert a Futhark record into an SML record with values, you must still also free the original Futhark record at some point. donβt forget the cleanup era π§Ή
π SUM TYPES π
Each sum type is represented by a structure implementing the signature below.
signature FUTHARK_SUM =
sig
include FUTHARK_OPAQUE
type sum
val values: t -> sum
val new: ctx -> sum -> t
end
Any struct that implements this signature will define the type sum to be an SML mirror of the Futhark-level sum type. Note that if you convert a Futhark sum type value into an SML value with values, you must still also free the original Futhark object at some point. same energy as records, bestie β free the original π
ποΈ ARRAYS OF RECORDS ποΈ
Each array of records is represented by a structure implementing the signature below.
signature FUTHARK_RECORD_ARRAY =
sig
include FUTHARK_OPAQUE
type shape
type index
type elem
type fields
val shape: t -> shape
val index: t -> index -> elem
val zip : fields -> t
end
The shape, index, and elem types are similar to the corresponding types in the FUTHARK_ARRAY signature. The fields type will be refined to a tuple of Futhark array types, which can be zipped together (using zip) to produce an array of records. Raises Size if the arrays do not have matching shapes (up to the rank of the record array type). shape check or itβs a no from me β
π§ ARRAYS OF OPAQUES π§
Each array of opaque non-records is represented by a structure implementing the signature below.
signature FUTHARK_OPAQUE_ARRAY =
sig
include FUTHARK_OPAQUE
type shape
type index
type elem
val shape: t -> shape
val index: t -> index -> elem
end
The shape, index, and elem types are similar to the corresponding types in the FUTHARK_ARRAY signature. In practice, this signature is used only for arrays comprised of sum type values. niche but iconic π«Ά
πͺ ENTRY POINTS πͺ
Each Futhark entry point becomes a function with two parameters: the context object, and a tuple with one element per parameter of the original Futhark function. main character function energy π
π LINKING FUTHARK WITH MLTON π
The Futhark compiler produces C code, which must be passed to mlton(1) in order to produce an executable. This can be done simply by passing the .c file to mlton(1) on the command line, along with the .sml and/or .mlb file. However, if you want to use a GPU backend, you must also pass the appropriate linker flags, e.g.
mlton foo.mlb foo.c foo.smlfut.c -link-opt '-lcuda -lnvrtc -lcudart'
for CUDA. GPU girlies rise π
Note that foo.c is the file produced by futhark(1), while foo.smlfut.c is the file generated by smlfut. See the Futhark documentation for the appropriate linker flags needed for a given backend. read the docs, bestie β itβs giving necessary π
π§© LINKING FUTHARK WITH MLKIT π§©
The same general concerns apply with MLKit as with MLton. To link with MLKit, you must compile the C file generated by the Futhark compiler, foo.c, and the C file produced by smlfut foo.smlfut.c, to object files foo.o and foo.smlfut.o, and then combine them to a single archive file with
ar r libfoo.a test.o test.smlfut.o
The libfoo.a file can then be supplied to MLKit by passing
-libs m,c,dl,test
on the command line (along with other relevant linker flags). archive and deliver β¨
π BUGS π
- The generated code currently supports only MLton, MPL, and MLKit.
- The generated code directly exposes the manual memory management required by Futharkβs C interface. If you neglect to free the values built using constructor functions or entry points, you will leak memory. Freeing the context before freeing all associated values will also leak memory. memory leak jumpscare π
- Be careful not to mix values associated with different contexts. They have the same type, so this is an easy mistake to make. same type does NOT mean same context, bestie β stay safe π
π LICENSE π
smlfut itself is released under the GPLv3 or later. The code generated by smlfut may be used for any purpose, without restrictions or requirements, without any need for attribution. generated code says free to use, no attribution needed β we love a generous queen π
π okay thatβs the whole page, bestie β brought to you by DIKU Β· 2024 Β· smlfut(1). mwah π
π¦ where this page comes from
- nixos 26.05: smlfut 1.6.4
- nixpkgs unstable: smlfut 1.6.4
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms