@@ -472,41 +472,93 @@ function gc_bytes()
472
472
b[]
473
473
end
474
474
475
- function allocated (f, args:: Vararg{Any,N} ) where {N}
475
+ @constprop :none function allocated (f, args:: Vararg{Any,N} ) where {N}
476
476
b0 = Ref {Int64} (0 )
477
477
b1 = Ref {Int64} (0 )
478
478
Base. gc_bytes (b0)
479
- f (args... )
479
+ @noinline f (args... )
480
480
Base. gc_bytes (b1)
481
481
return b1[] - b0[]
482
482
end
483
483
only (methods (allocated)). called = 0xff
484
484
485
- function allocations (f, args:: Vararg{Any,N} ) where {N}
485
+ @constprop :none function allocations (f, args:: Vararg{Any,N} ) where {N}
486
486
stats = Base. gc_num ()
487
- f (args... )
487
+ @noinline f (args... )
488
488
diff = Base. GC_Diff (Base. gc_num (), stats)
489
489
return Base. gc_alloc_count (diff)
490
490
end
491
491
only (methods (allocations)). called = 0xff
492
492
493
493
function is_simply_call (@nospecialize ex)
494
+ is_simple_atom (a) = a isa QuoteNode || a isa Symbol || ! isa_ast_node (a)
494
495
Meta. isexpr (ex, :call ) || return false
495
496
for a in ex. args
496
- a isa QuoteNode && continue
497
- a isa Symbol && continue
498
- isa_ast_node (a) || continue
497
+ is_simple_atom (a) && continue
498
+ Meta. isexpr (a, :... , 1 ) && is_simple_atom (a. args[1 ]) && continue
499
499
return false
500
500
end
501
501
return true
502
502
end
503
503
504
+ function _gen_allocation_measurer (ex, fname:: Symbol )
505
+ if isexpr (ex, :call )
506
+ if ! is_simply_call (ex)
507
+ ex = :((() -> $ ex)())
508
+ end
509
+ pushfirst! (ex. args, GlobalRef (Base, fname))
510
+ return quote
511
+ Experimental. @force_compile
512
+ $ (esc (ex))
513
+ end
514
+ elseif fname === :allocated
515
+ # v1.11-compatible implementation
516
+ return quote
517
+ Experimental. @force_compile
518
+ local b0 = Ref {Int64} (0 )
519
+ local b1 = Ref {Int64} (0 )
520
+ gc_bytes (b0)
521
+ $ (esc (ex))
522
+ gc_bytes (b1)
523
+ b1[] - b0[]
524
+ end
525
+ else
526
+ @assert fname === :allocations
527
+ return quote
528
+ Experimental. @force_compile
529
+ # Note this value is unused, but without it `allocated` and `allocations`
530
+ # are sufficiently different that the compiler can remove allocations here
531
+ # that it cannot remove there, giving inconsistent numbers.
532
+ local b1 = Ref {Int64} (0 )
533
+ local stats = Base. gc_num ()
534
+ $ (esc (ex))
535
+ local diff = Base. GC_Diff (Base. gc_num (), stats)
536
+ gc_bytes (b1)
537
+ Base. gc_alloc_count (diff)
538
+ end
539
+ end
540
+ end
541
+
504
542
"""
505
543
@allocated
506
544
507
545
A macro to evaluate an expression, discarding the resulting value, instead returning the
508
546
total number of bytes allocated during evaluation of the expression.
509
547
548
+ If the expression is a function call, an effort is made to measure only allocations from
549
+ the argument expressions and during the function, excluding any overhead from calling it
550
+ and not performing constant propagation with the provided argument values. If you want to
551
+ include those effects, i.e. measuring the call site as well, use the syntax
552
+ `@allocated (()->f(1))()`.
553
+
554
+ It is recommended to measure function calls with only simple argument expressions, e.g.
555
+ `x = []; @allocated f(x)` instead of `@allocated f([])` to clarify that only `f` is
556
+ being measured.
557
+
558
+ For more complex expressions, the code is simply run in place and therefore may see
559
+ allocations due to the surrounding context. For example it is possible for
560
+ `@allocated f(1)` and `@allocated x = f(1)` to give different results.
561
+
510
562
See also [`@allocations`](@ref), [`@time`](@ref), [`@timev`](@ref), [`@timed`](@ref),
511
563
and [`@elapsed`](@ref).
512
564
@@ -516,11 +568,7 @@ julia> @allocated rand(10^6)
516
568
```
517
569
"""
518
570
macro allocated (ex)
519
- if ! is_simply_call (ex)
520
- ex = :((() -> $ ex)())
521
- end
522
- pushfirst! (ex. args, GlobalRef (Base, :allocated ))
523
- return esc (ex)
571
+ _gen_allocation_measurer (ex, :allocated )
524
572
end
525
573
526
574
"""
@@ -541,11 +589,7 @@ julia> @allocations rand(10^6)
541
589
This macro was added in Julia 1.9.
542
590
"""
543
591
macro allocations (ex)
544
- if ! is_simply_call (ex)
545
- ex = :((() -> $ ex)())
546
- end
547
- pushfirst! (ex. args, GlobalRef (Base, :allocations ))
548
- return esc (ex)
592
+ _gen_allocation_measurer (ex, :allocations )
549
593
end
550
594
551
595
0 commit comments