Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove usages of environment-map #1350

Merged
merged 1 commit into from
Jan 14, 2025

Conversation

jbouwman
Copy link
Collaborator

Environment maps were introduced in order to provide platform-agnostic
dumping of hashtables present in Coalton environment structures.

A review of the three locations where these maps are
present (method-codegen-sym, class-variable-map, superclass-map)
indicates that in all cases, a simple list or alist structure is more
appropriate because of the small number of elements consulted.

In particular, method-codegen-syms are 1-1 with the method-names list,
so no mapping is needed at all.

@jbouwman jbouwman changed the title Environment map Remove usages of environment-map Jan 10, 2025
Copy link
Collaborator

@Izaakwltn Izaakwltn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only thought would be to run some sort of benchmark to make sure this is comparable or faster.

Otherwise, looks good!

src/typechecker/define-class.lisp Show resolved Hide resolved
@@ -1382,14 +1373,20 @@
entry)
#'make-fundep-environment))))

(defun class-variable-map (class)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I like the spirit of this PR, but when I compiled coalton and coalton/testwith the following extra lines, there are cases where this function is run as many as 90 times on a single class. On the other hand, this function is, overall, not called that many times. I printed the results below.

(defvar *called-class-variable-map-p-table* (make-hash-table :test 'eq))

(defun class-variable-map (class)
  (format t "Call number ~D on this class." (incf (gethash class *called-class-variable-map-p-table* 0)))
  (loop :with table := (make-hash-table)
        :for var :in (ty-class-class-variables class)
        :for i :from 0
        :do (setf (gethash var table) i)
        :finally (return table)))

Running (asdf:load-system "coalton" :force t)

Called class-variable-map 171 times on TRYINTO
Called class-variable-map 6 times on RANDOMACCESS
Called class-variable-map 2 times on INTOITERATOR
Called class-variable-map 116 times on INTOITERATOR
Called class-variable-map 71 times on FROMITERATOR
Called class-variable-map 2 times on RANDOMACCESS
Called class-variable-map 94 times on ADD
Called class-variable-map 71 times on FIB
Called class-variable-map 2 times on ADD
Called class-variable-map 3 times on FIB
Called class-variable-map 2 times on C
Called class-variable-map 2 times on C
Called class-variable-map 2 times on C
Called class-variable-map 2 times on C
Called class-variable-map 2 times on C
Called class-variable-map 4 times on C
Called class-variable-map 3 times on MOO
Called class-variable-map 2 times on C
Called class-variable-map 2 times on C
Called class-variable-map 2 times on C
Called class-variable-map 84 times on TRYINTO
Called class-variable-map 69 times on INTOITERATOR
Called class-variable-map 46 times on FROMITERATOR
Called class-variable-map 1 times on RANDOMACCESS
Called class-variable-map 2 times on ADD
Called class-variable-map 3 times on FIB
Called class-variable-map 94 times on ADD
Called class-variable-map 71 times on FIB
Called class-variable-map 2 times on ADD
Called class-variable-map 3 times on FIB
Called class-variable-map 171 times on TRYINTO
Called class-variable-map 6 times on RANDOMACCESS
Called class-variable-map 2 times on INTOITERATOR
Called class-variable-map 110 times on INTOITERATOR
Called class-variable-map 68 times on FROMITERATOR
Called class-variable-map 2 times on RANDOMACCESS
Called class-variable-map 94 times on ADD
Called class-variable-map 71 times on FIB
Called class-variable-map 2 times on ADD
Called class-variable-map 3 times on FIB
Called class-variable-map 171 times on TRYINTO
Called class-variable-map 6 times on RANDOMACCESS
Called class-variable-map 2 times on INTOITERATOR
Called class-variable-map 110 times on INTOITERATOR
Called class-variable-map 68 times on FROMITERATOR
Called class-variable-map 2 times on RANDOMACCESS
Called class-variable-map 94 times on ADD
Called class-variable-map 71 times on FIB
Called class-variable-map 2 times on ADD
Called class-variable-map 3 times on FIB
Called class-variable-map 171 times on TRYINTO
Called class-variable-map 6 times on RANDOMACCESS
Called class-variable-map 2 times on INTOITERATOR
Called class-variable-map 54 times on INTOITERATOR
Called class-variable-map 33 times on FROMITERATOR
Called class-variable-map 2 times on RANDOMACCESS

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than this, I don't think I have any comments, I like +62 vs -208 LOC 😎

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And 9 of those are docstrings :)

@jbouwman
Copy link
Collaborator Author

Following up @Izaakwltn's suggestion to check benchmarking, repeated runs of the test suite don't flag obvious performance regressions. That's tempered by the knowledge that there's not good coverage for, e.g., superclasses.

That class-variable-map in particular is almost always trivially small -- never above 7 entries, for standard library and tests -- and possibly ought to be an alist -- and possibly memoized.

Test

(time (dotimes (x 50) (asdf:test-system "coalton")))

Main

Evaluation took:
  238.551 seconds of real time
  180.034131 seconds of total run time (171.736752 user, 8.297379 system)
  [ Real times consist of 12.984 seconds GC time, and 225.567 seconds non-GC time. ]
  [ Run times consist of 12.982 seconds GC time, and 167.053 seconds non-GC time. ]
  75.47% CPU
  7,816,750 forms interpreted
  177,700 lambdas converted
  93,144,529,824 bytes consed

environment-map

Evaluation took:
  203.295 seconds of real time
  179.135658 seconds of total run time (170.922189 user, 8.213469 system)
  [ Real times consist of 13.827 seconds GC time, and 189.468 seconds non-GC time. ]
  [ Run times consist of 13.827 seconds GC time, and 165.309 seconds non-GC time. ]
  88.12% CPU
  7,798,750 forms interpreted
  177,700 lambdas converted
  92,756,680,592 bytes consed

@stylewarning
Copy link
Member

I'll take a look.

Copy link
Member

@stylewarning stylewarning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay on this. I have one very modest request which is to be very explicit on what a data type is.

(fundeps (util:required 'fundeps) :type fundep-list :read-only t)

;; Methods of the class containing the same tyvars in PREDICATE for
;; use in pretty printing
(unqualified-methods (util:required 'unqualified-methods) :type ty-class-method-list :read-only t)
(codegen-sym (util:required 'codegen-sym) :type symbol :read-only t)
(superclass-dict (util:required 'superclass-dict) :type list :read-only t)
(superclass-map (util:required 'superclass-map) :type environment-map :read-only t)
(superclass-map (util:required 'superclass-map) :type list :read-only t)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write a comment describing the keys and values here? I don't think "list" is self-evident. Something like

;; an immutable alist of the form ((a1 b1) ...) whose keys are ... and values are ...

clarify if it's an alist of lists or an alist of conses.

I would say this is the sole and biggest negative of this change, we are using an ad hoc data structure.

Environment maps were introduced in order to provide platform-agnostic
dumping of hashtables present in Coalton environment structures.

A review of the three locations where these maps are
present (method-codegen-sym, class-variable-map, superclass-map)
indicates that in all cases, a simple list or alist structure is more
appropriate because of the small number of elements consulted.

In particular, method-codegen-syms are 1-1 with the method-names list,
so no mapping is needed.
@stylewarning stylewarning merged commit b504749 into coalton-lang:main Jan 14, 2025
25 checks passed
@jbouwman jbouwman deleted the environment-map branch January 18, 2025 17:06
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