]> gitweb.factorcode.org Git - factor.git/commitdiff
working on docs, measuring gc time
authorSlava Pestov <slava@factorcode.org>
Tue, 23 Nov 2004 00:15:14 +0000 (00:15 +0000)
committerSlava Pestov <slava@factorcode.org>
Tue, 23 Nov 2004 00:15:14 +0000 (00:15 +0000)
14 files changed:
TODO.FACTOR.txt
doc/new-guide.tex
library/platform/native/vectors.factor
library/test/inference.factor
library/test/test.factor
library/tools/cross-compiler.factor
library/tools/inference.factor
native/factor.c
native/gc.c
native/gc.h
native/misc.c
native/misc.h
native/primitives.c
native/primitives.h

index 024ec076d5f359f3d9538494d1b8c7ba6b7cb005..8d0d2353d211b32614f8df64f84531d1c447e49d 100644 (file)
@@ -4,7 +4,6 @@
 - type inference\r
 - some way to step over a word in the stepper\r
 - step: print NEXT word to execute, not word that JUST executed\r
-- cache stack effects\r
 - once generic inference is done, can-compile is "has stack effect!"\r
 \r
 + compiler/ffi:\r
index 883cc843594431b0a5618d2b4202b6fbc15dbdef..c5dfdbf625d4115c904c0115343076092e028d87 100644 (file)
@@ -1,4 +1,4 @@
-% :indentSize=4:tabSize=4:noTabs=true:mode=tex:
+% :indentSize=4:tabSize=4:noTabs=true:mode=tex:wrap=soft:
 
 \documentclass[english]{book}
 \makeindex
@@ -173,18 +173,18 @@ You can look at the definition of any word, including library words, using \text
     "Greetings, " write print ;}
 \end{alltt}
 
-%\sidebar{
-%Factor is written in itself. Indeed, most words in the Factor library are colon definitions, defined in terms of other words. Out of more than two thousand words in the Factor library, less than two hundred are \emph{primitive}, or built-in to the runtime.
-%
-%If you exit Factor by typing \texttt{exit}, any colon definitions entered at the listener will be lost. However, you can save a new image first, and use this image next time you start Factor in order to have access to  your definitions.
-%
-%\begin{alltt}
-%\textbf{ok} "work.image" save-image\\
-%\textbf{ok} exit
-%\end{alltt}
-%
-%The \texttt{factor.image} file you start with initially is just an image that was saved after the standard library, and nothing else, was loaded.
-%}
+\sidebar{
+Factor is written in itself. Indeed, most words in the Factor library are colon definitions, defined in terms of other words. Out of more than two thousand words in the Factor library, less than two hundred are \emph{primitive}, or built-in to the runtime.
+
+If you exit Factor by typing \texttt{exit}, any colon definitions entered at the listener will be lost. However, you can save a new image first, and use this image next time you start Factor in order to have access to  your definitions.
+
+\begin{alltt}
+\textbf{ok} "work.image" save-image\\
+\textbf{ok} exit
+\end{alltt}
+
+The \texttt{factor.image} file you start with initially is just an image that was saved after the standard library, and nothing else, was loaded.
+}
 
 \section{The stack}
 
@@ -897,6 +897,109 @@ Test if a value is a proper list.\\
 
 \section{Combinators}
 
+\chapkeywords{when unless when* unless* ifte*}
+\index{\texttt{when}}
+\index{\texttt{unless}}
+\index{\texttt{when*}}
+\index{\texttt{unless*}}
+\index{\texttt{ifte*}}
+
+A \emph{combinator} is a word that takes a code quotation on the stack. In this section, we will look at some simple combinators, all derived from the fundamental \texttt{ifte} combinator we saw earlier. A later section will cover recursive combinators, used for iteration over lists and such.
+
+You may have noticed the curious form of conditional expressions we have seen so far. Indeed, the two code quotations given as branches of the conditional look just like lists, and \texttt{ifte} looks like a normal word that takes these two lists from the stack:
+
+\begin{alltt}
+\emph{condition} {[}
+    \emph{to execute if true}
+{] [}
+    \emph{to execute if false}
+{]} ifte
+\end{alltt}
+
+The \texttt{ifte} word is a \emph{combinator}, because it executes lists representing code, or \emph{quotations}, given on the stack.
+
+%We have already seen the \texttt{when} combinator, which is similar to \texttt{ifte} except it only takes one quotation; the quotation is executed if the condition is true, and nothing is done if the condition is false. In fact \texttt{when} is implemented in terms of \texttt{ifte}. If you think about it for a brief moment, since \texttt{when} is called with a quotation on the stack, it suffices to push an empty list, and call \texttt{ifte}:
+%
+%\begin{verbatim}
+%: when ( ? quot -- )
+%    [ ] ifte ;
+%\end{verbatim}
+%
+%An example of a word that uses both \texttt{ifte} and \texttt{when} is the \texttt{abs} word, which computes the absolute value of a number:
+%
+%\begin{verbatim}
+%: abs ( z -- abs )
+%    #! Compute the complex absolute value.
+%    dup complex? [
+%        >rect mag2
+%    ] [
+%        dup 0 < [ neg ] when
+%    ] ifte ;
+%\end{verbatim}
+%
+%If the given number is a complex number, its distance from the origin is computed\footnote{Don't worry about the \texttt{>rect} and \texttt{mag2} words at this stage; they will be described later. If you are curious, use \texttt{see} to look at their definitions and read the documentation comments.}. Otherwise, if the parameter is a real number below zero, it is negated. If it is a real number greater than zero, it is not modified.
+
+% Note that each branch has the same stack effect. You can use the \texttt{infer} combinator to verify this:
+% 
+% \begin{alltt}
+% \textbf{ok} [ >rect mag2 ] infer .
+% \textbf{[ 1 | 1 ]}
+% \textbf{ok} [ dup 0 < [ neg ] when ] infer .
+% \textbf{[ 1 | 1 ]}
+% \end{alltt}
+% 
+% Hence, the stack effect of the entire conditional expression can be computed:
+% 
+% \begin{alltt}
+% \textbf{ok} [ abs ] infer .
+% \textbf{[ 1 | 1 ]}
+% \end{alltt}
+
+%The dual of the \texttt{when} combinator is the \texttt{unless} combinator. It takes a quotation to execute if the condition is false; otherwise nothing is done. In both cases, the condition is popped off the stack.
+%
+%The implementation is similar to that of \texttt{when}, but this time, we must swap the two quotations given to \texttt{ifte}, so that the true branch is an empty list, and the false branch is the user's quotation:
+%
+%\begin{verbatim}
+%: unless ( ? quot -- )
+%    [ ] swap ifte ;
+%\end{verbatim}
+%
+%A very simple example of \texttt{unless} usage is the \texttt{assert} word:
+%
+%\begin{verbatim}
+%: assert ( t -- )
+%    [ "Assertion failed!" throw ] unless ;
+%\end{verbatim}
+
+%Lets take a look at the words we saw in this section:
+%
+%\wordtable{
+%\tabvocab{combinators}
+%\texttt{when}&
+%\texttt{( ?~quot -{}- )}&
+%Execute quotation if the condition is true, otherwise do nothing but pop the condition and quotation off the stack.\\
+%\texttt{unless}&
+%\texttt{( ?~quot -{}- )}&
+%Execute quotation if the condition is false, otherwise do nothing but pop the condition and quotation off the stack.\\
+%\texttt{when*}&
+%\texttt{( ?~quot -{}- )}&
+%If the condition is true, execute the quotation, with the condition on the stack. Otherwise, pop the condition off the stack.\\
+%\texttt{unless*}&
+%\texttt{( ?~quot -{}- )}&
+%If the condition is false, pop the condition and execute the quotation. Otherwise, leave the condition on the stack.\\
+%\texttt{ifte*}&
+%\texttt{( ?~true false -{}- )}&
+%If condition is true, execute the true branch, with the condition on the stack. Otherwise, pop the condition off the stack and execute the false branch.\\
+%\tabvocab{math}
+%\texttt{ans}&
+%\texttt{( z -- abs )}&
+%Compute the complex absolute value.\\
+%\tabvocab{test}
+%\texttt{assert}&
+%\texttt{( t -- )}&
+%Raise an error if the top of the stack is \texttt{f}.\\
+%}
+
 \section{The interpreter}
 
 \chapkeywords{acons >r r>}
@@ -908,7 +1011,7 @@ So far, we have seen what we called ``the stack'' store intermediate values betw
 
 Another fundamental stack is the \emph{return stack}. It is used to save interpreter state for nested calls.
 
-You have probably noticed that code quotations are just lists. At a low level, each colon definition is also just a quotation. The interpreter consists of a loop that iterates a quotation, pushing each literal, and executing each word. If the word is a colon definition, the interpreter saves its state on the return stack, executes the definition of that word, then restores the execution state from the return stack and continues.
+You already know that code quotations are just lists. At a low level, each colon definition is also just a quotation. The interpreter consists of a loop that iterates a quotation, pushing each literal, and executing each word. If the word is a colon definition, the interpreter saves its state on the return stack, executes the definition of that word, then restores the execution state from the return stack and continues.
 
 The return stack also serves a dual purpose as a temporary storage area. Sometimes, juggling values on the data stack becomes ackward, and in that case \texttt{>r} and \texttt{r>} can be used to move a value from the data stack to the return stack, and vice versa, respectively.
 
@@ -950,9 +1053,6 @@ Move value to return stack..\\
 Move value from return stack..\\
 }
 
-\section{Word definitions}
-
-
 \section{Recursive combinators}
 
 \section{Unit testing}
index cc4d795d80e4d4f25085d9d87d1679fd4a06b2b8..a77d9d6cbf2bfe12c2d7131e9dd8803ba7090b3e 100644 (file)
@@ -48,7 +48,7 @@ USE: stack
     ] ifte ;
 
 : vector-length= ( vec vec -- ? )
-    vector-length swap vector-length = ;
+    vector-length swap vector-length number= ;
 
 : vector= ( obj vec -- ? )
     #! Check if two vectors are equal. Two vectors are
index 004a02160ba82e4bf082bf479f2aa4195ee043f8..78ae5468d5b420ffc75dfa579b5a20bd45914f89 100644 (file)
@@ -20,11 +20,11 @@ USE: namespaces
     [ 3 | 4 ]
 ] "effects" set
 
-[ t ] [
-    "effects" get [
-        dup [ 7 | 7 ] decompose compose [ 7 | 7 ] =
-    ] all?
-] unit-test
+[ t ] [
+    "effects" get [
+        dup [ 7 | 7 ] decompose compose [ 7 | 7 ] =
+    ] all?
+] unit-test
 [ 6 ] [ 6 gensym-vector vector-length ] unit-test
 
 [ 3 ] [ [ { 1 2 } { 1 2 3 } ] max-vector-length ] unit-test
@@ -146,7 +146,7 @@ DEFER: foe
 [ [ 1 | 1 ] ] [ [ length ] infer ] unit-test
 [ [ 1 | 1 ] ] [ [ reverse ] infer ] unit-test
 [ [ 2 | 1 ] ] [ [ contains? ] infer ] unit-test
-[ [ 2 | 1 ] ] [ [ contains? ] infer ] unit-test
+[ [ 2 | 1 ] ] [ [ tree-contains? ] infer ] unit-test
 [ [ 2 | 1 ] ] [ [ remove ] infer ] unit-test
 
 [ [ 2 | 1 ] ] [ [ bitor ] infer ] unit-test
index dc5ac1083fbfe7dc2bbb10c6d5a204d1dd57bb9a..df20d42e271bcbda4220cacf02b5ec5ab5b91764 100644 (file)
@@ -30,8 +30,9 @@ USE: unparser
 : time ( code -- )
     #! Evaluates the given code and prints the time taken to
     #! execute it.
-    millis >r call millis r> -
-    unparse write " milliseconds" print ;
+    millis >r gc-time >r call gc-time r> - millis r> -
+    unparse write " milliseconds run time" print
+    unparse write " milliseconds GC time" print ;
 
 : unit-test ( output input -- )
     [
index b29e82a2849d0f01209ac78477a55b14597e11dd..8bbf796c90944218b02f09cdafeda2c18e8d0f91 100644 (file)
@@ -66,6 +66,7 @@ DEFER: literal-top
 DEFER: set-literal-top
 
 IN: kernel
+DEFER: gc-time
 DEFER: getenv
 DEFER: setenv
 DEFER: save-image
@@ -325,6 +326,7 @@ IN: image
         stat
         (directory)
         garbage-collection
+        gc-time
         save-image
         datastack
         callstack
index b997ed4659638e7c15c0c9ee0e8077e74ab01174..1b3d718bcae62766c0ced7d7bac9780ed3011400 100644 (file)
@@ -130,21 +130,26 @@ DEFER: (infer)
     call
     recursive-state uncons@ drop ;
 
-: recursive-infer ( quot -- )
+: infer-word ( word -- )
+    #! Infer a word's stack effect, and cache it.
     [
         recursive-state get init-inference
-        (infer)  effect
+        [
+            dup word-parameter (infer) effect
+            [ "infer-effect" set-word-property ] keep
+        ] with-recursive-state
     ] with-scope ;
 
+: inline-compound ( word -- )
+    [ word-parameter (infer) ] with-recursive-state ;
+
 : apply-compound ( word -- )
     #! Infer a compound word's stack effect.
     [
-        word-parameter [
-            recursive-infer consume/produce
-        ] [
-            [ (infer) ] when
-        ] catch
-    ] with-recursive-state ;
+        infer-word consume/produce
+    ] [
+        [ inline-compound ] when
+    ] catch ;
 
 : apply-word ( word -- )
     #! Apply the word's stack effect to the inferencer state.
@@ -256,11 +261,14 @@ DEFER: (infer)
     >r uncons r> uncons >r -
     dup 0 < [ neg + r> cons ] [ r> + cons ] ifte ;
 
+: raise ( [ in | out ] -- [ in | out ] )
+    uncons 2dup min tuck - >r - r> cons ;
+
 : decompose ( first second -- solution )
     #! Return a stack effect such that first*solution = second.
     2dup 2car
     2dup > [ "No solution to decomposition" throw ] when
-    swap - -rot 2cdr >r + r> cons ;
+    swap - -rot 2cdr >r + r> cons raise ;
 
 : set-base ( [ in | stack ] -- )
     #! Set the base case of the current word.
@@ -312,7 +320,7 @@ DEFER: (infer)
 
 : meta-infer ( word -- )
     #! Mark a word as being partially evaluated.
-    dup unit [ car meta-word ] cons  "infer" set-word-property ;
+    dup unit [ car host-word ] cons  "infer" set-word-property ;
 
 \ call [ pop-d (infer) ] "infer" set-word-property
 \ ifte [ infer-ifte ] "infer" set-word-property
index 67f2ff9bd032626a4f9f4d0302a24cc8912c8a5b..027a2a87c7eee25bc52e2880388c2e88327d1d9b 100644 (file)
@@ -1,5 +1,23 @@
 #include "factor.h"
 
+void init_factor(char* image)
+{
+       init_arena(DEFAULT_ARENA);
+       load_image(image);
+       init_stacks();
+       init_io();
+       init_signals();
+       init_compiler();
+       init_errors();
+       gc_time = 0;
+
+#ifdef FACTOR_X86
+       userenv[CPU_ENV] = tag_object(from_c_string("x86"));
+#else
+       userenv[CPU_ENV] = tag_object(from_c_string("unknown"));
+#endif
+}
+
 int main(int argc, char** argv)
 {
        CELL args;
@@ -12,13 +30,7 @@ int main(int argc, char** argv)
                return 1;
        }
 
-       init_arena(DEFAULT_ARENA);
-       load_image(argv[1]);
-       init_stacks();
-       init_io();
-       init_signals();
-       init_compiler();
-       init_errors();
+       init_factor(argv[1]);
 
        args = F;
        while(--argc != 0)
@@ -28,12 +40,6 @@ int main(int argc, char** argv)
 
        userenv[ARGS_ENV] = args;
 
-#ifdef FACTOR_X86
-       userenv[CPU_ENV] = tag_object(from_c_string("x86"));
-#else
-       userenv[CPU_ENV] = tag_object(from_c_string("unknown"));
-#endif
-
        run();
 
        return 0;
index 0dcdc7999b72aa2184b23697f43528588b8fbf85..b3e72d21e6fa6bfb062785ba3b3f416a31913959 100644 (file)
@@ -132,6 +132,8 @@ void collect_roots(void)
 
 void primitive_gc(void)
 {
+       long long start = current_millis();
+
        gc_in_progress = true;
 
        flip_zones();
@@ -148,6 +150,8 @@ void primitive_gc(void)
        gc_debug("gc done",0);
 
        gc_in_progress = false;
+
+       gc_time += (current_millis() - start);
 }
 
 /* WARNING: only call this from a context where all local variables
@@ -157,3 +161,9 @@ void maybe_garbage_collection(void)
        if(active.here > active.alarm)
                primitive_gc();
 }
+
+void primitive_gc_time(void)
+{
+       maybe_garbage_collection();
+       dpush(tag_object(s48_long_long_to_bignum(gc_time)));
+}
index c6e1b0f907230116999eca7b95f05c99c8760f42..a1426d808dc8eb878d374dc7c69e56d2cac39758 100644 (file)
@@ -1,5 +1,6 @@
 CELL scan;
 bool gc_in_progress;
+long long gc_time;
 
 void* copy_untagged_object(void* pointer, CELL size);
 void copy_object(CELL* handle);
@@ -8,3 +9,4 @@ void collect_next(void);
 void collect_roots(void);
 void primitive_gc(void);
 void maybe_garbage_collection(void);
+void primitive_gc_time(void);
index 137032a05635c0ee76f7b31c9d49384a14898e90..fa82d091a9c86fa1afa3066a458241209a659d9c 100644 (file)
@@ -24,13 +24,17 @@ void primitive_eq(void)
        box_boolean(dpop() == dpop());
 }
 
-void primitive_millis(void)
+long long current_millis(void)
 {
        struct timeval t;
        gettimeofday(&t,NULL);
+       return (long long)t.tv_sec * 1000 + t.tv_usec/1000;
+}
+
+void primitive_millis(void)
+{
        maybe_garbage_collection();
-       dpush(tag_object(s48_long_long_to_bignum(
-               (long long)t.tv_sec * 1000 + t.tv_usec/1000)));
+       dpush(tag_object(s48_long_long_to_bignum(current_millis())));
 }
 
 void primitive_init_random(void)
index 8118ef2959321d0f96033edb85842f7288b30e69..edf46e179ada600a77c5c3e9eaf6544de4bfe8d1 100644 (file)
@@ -1,6 +1,7 @@
 void primitive_exit(void);
 void primitive_os_env(void);
 void primitive_eq(void);
+long long current_millis(void);
 void primitive_millis(void);
 void primitive_init_random(void);
 void primitive_random_int(void);
index 9f7c9d72273cc3e1584466dd6695b89eb4a2f409..bb709b82f59bd724d73f52b46fabeeca453b5f2d 100644 (file)
@@ -137,6 +137,7 @@ XT primitives[] = {
        primitive_stat,
        primitive_read_dir,
        primitive_gc,
+       primitive_gc_time,
        primitive_save_image,
        primitive_datastack,
        primitive_callstack,
index c41f8b479683b3598b4042b856963ede5a3bc84d..1aa49ac28140a009df69e8ae1f2e8e2ec6c3c589 100644 (file)
@@ -1,4 +1,4 @@
 extern XT primitives[];
-#define PRIMITIVE_COUNT 191
+#define PRIMITIVE_COUNT 192
 
 CELL primitive_to_xt(CELL primitive);