Skip to content

Allocation at nonexisting line #87

@ForceBru

Description

@ForceBru

I've just wasted like 2 hours trying to debug some code, only to find that the allocation happens at a line that doesn't exist. Also seems to always be line 139, irrespective of the number of line in my code.

This code has 83 lines:

import Pkg
Pkg.activate(temp=true)
Pkg.add(name="AllocCheck", version="0.2.0")

import Random
using AllocCheck

const AV{T} = AbstractVector{T}

struct Prealloc{T<:Real}
	As::Vector{T}
	Bs::Vector{T}
	Cs::Vector{T}
	qs::Vector{T}
	function Prealloc(As::AV{T}, Bs::AV{T}, Cs::AV{T}, qs::AV{T}) where T<:Real
		@warn "Preallocating" length(As)
		@assert length(As) == length(Bs) == length(Cs) == length(qs)
		new{T}(As, Bs, Cs, qs)
	end
end

Prealloc{T}(K::Integer) where T<:Real =
	Prealloc(zeros(T, K), zeros(T, K), zeros(T, K), zeros(T, K))

Prealloc(K::Integer) = Prealloc{Float64}(K)

@check_allocs function step_mle!(
	ps::AV{T}, ms::AV{T}, ts::AV{T}, data::AV{<:Real},
	l2norm::Bool, lmb::Real, aux::Prealloc{T}
) where T<:Real
	As, Bs, Cs, qs = aux.As, aux.Bs, aux.Cs, aux.qs
	As .= zero(T); Bs .= zero(T); Cs .= zero(T)
	nothing
end

struct Mixture{T<:Real}
	ps::Vector{T}
	ms::Vector{T}
	ts::Vector{T}
	function Mixture(ps::AV{T}, ms::AV{T}, ts::AV{T}) where T<:Real
		@assert length(ps) == length(ms) == length(ts)	
		new{T}(ps, ms, ts)
	end
end

rand_categorical(rng::Random.AbstractRNG, weights::AV)::Integer =
	findfirst(cumsum(weights) .> rand(rng))

Random.rand(
	rng::Random.AbstractRNG, d::Mixture{T}
) where T<:Real = begin
	k = rand_categorical(rng, d.ps);
	randn(rng, T) / d.ts[k] + d.ms[k]
end

function Random.rand(d::Mixture, n::Integer)
	rng = Random.default_rng()
	[rand(rng, d) for _ in 1:n]
end

@check_allocs function fit_basic!(
	mix::Mixture{T}, data::AV{<:Real};
	niter::Integer=300,
	aux::Prealloc{T}
) where T<:Real
	ps, ms, ts = mix.ps, mix.ms, mix.ts
	for ep in 1:niter
		step_mle!(ps, ms, ts, data, true, 0.0, aux) # LINE 68
	end
end

let
	K = 50
	mix0 = Mixture(ones(K) ./ K, randn(K), rand(K))
	data = rand(mix0, 200);
	aux = Prealloc(K)

	try
		fit_basic!(mix0, data; aux, niter=2000)
	catch err
		@show err.errors[1]
	end
end

Running this:

> julia --version
julia version 1.11.1
> julia test.jl
  Activating new project at `/var/folders/61/p7f15sln0gxd7lwbr58cy6f00000gn/T/jl_oQS2Dn`
   Resolving package versions...
    Updating `/private/var/folders/61/p7f15sln0gxd7lwbr58cy6f00000gn/T/jl_oQS2Dn/Project.toml`
  [9b6a8646] + AllocCheck v0.2.0
    Updating `/private/var/folders/61/p7f15sln0gxd7lwbr58cy6f00000gn/T/jl_oQS2Dn/Manifest.toml`
  [9b6a8646] + AllocCheck v0.2.0
...
  [3f19e933] + p7zip_jll v17.4.0+2
        Info Packages marked with ⌅ have new versions available but compatibility constraints restrict them from upgrading. To see why use `status --outdated -m`
┌ Warning: Preallocating
│   length(As) = 50
└ @ Main ~/Desktop/dev/test.jl:16
err.errors[1] = Allocating runtime call to "jl_f_getfield" in ./Base.jl:49
  | getproperty(x, f::Symbol) = (@inline; getfield(x, f))

Stacktrace:
 [1] getproperty
   @ ./Base.jl:49 [inlined]
 [2] step_mle!(ps::Vector{Float64}, ms::Vector{Float64}, ts::Vector{Float64}, data::Vector{Float64}, l2norm::Bool, lmb::Float64, aux::Prealloc{Float64})
   @ Main ~/Desktop/dev/test.jl:139
 [3] var"##fit_basic!#239"(mix::Mixture{Float64}, data::Vector{Float64}, niter::Int64, aux::Prealloc{Float64})
   @ Main ~/Desktop/dev/test.jl:68

> 

It says @ Main ~/Desktop/dev/test.jl:139, but there's no line 139! Same error happens in a longer file that I can't post here, also at line 139, no matter how I reorganize the code, no matter what code happens to be at line 139.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions