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

More demos #8

Merged
merged 2 commits into from
Jun 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions demos/abstract_analyze_versions.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using PyPlot

function parseline(line)
m = match(r"(.*) => (.*)", line)
sigstr, count = m.captures[1], parse(Int, m.captures[2])
sig = try
ex = Meta.parse(sigstr)
eval(ex)
catch
return nothing
end
return sig, count
end

function parsedata(filename)
lines = readlines(filename)
sigcount = IdDict{Any,Int}()
for line in lines
ret = parseline(line)
ret === nothing && continue
sig, count = ret
sigcount[sig] = count
end
return sigcount
end

function split_comparable(sigc1, sigc2)
c1, c2, sigs = Int[], Int[], Any[]
for (sig, c) in sigc1
push!(sigs, sig)
push!(c1, sigc1[sig])
push!(c2, get(sigc2, sig, 0))
end
for (sig, c) in sigc2
if !haskey(sigc1, sig)
push!(sigs, sig)
push!(c1, 0)
push!(c2, c)
end
end
return sigs, c1, c2
end

sigc16 = parsedata("/tmp/methdata_$VERSION.log")
sigc14 = parsedata("/tmp/methdata_1.4.3-pre.0.log")

sigs, c1, c2 = split_comparable(sigc14, sigc16)
mx1, mx2 = maximum(c1), maximum(c2)
isexported(sig) = (ft = Base.unwrap_unionall(sig).parameters[1]; isdefined(Main, ft.name.mt.name))
colors = [isexported(sig) ? "magenta" : "green" for sig in sigs]

function on_click(event)
x, y = event.xdata, event.ydata
normsqrdist(pr) = ((pr[1]-x)/mx1)^2 + ((pr[2]-y)/mx2)^2
idx = argmin(normsqrdist.(zip(c1, c2)))
println(sigs[idx])
end
begin
fig, ax = plt.subplots()
ax.scatter(c1 .+ 1, c2 .+ 1, c=colors) # + 1 for the log-scaling
ax.set_xlabel("# backedges + 1, 1.4")
ax.set_ylabel("# backedges + 1, 1.6")
ax.set_xscale("log")
ax.set_yscale("log")
fig.canvas.callbacks.connect("button_press_event", on_click)
fig
end

# Ones we've made progress on:
# ==(::Any, Symbol)
# ==(::Symbol, ::Any)
# ==(::Any, ::Nothing)
# ==(::UUID, ::Any)
# ==(::AbstractString, ::String)
# isequal(::Symbol, ::Any)
# isequal(::Any, ::Symbol)
# isequal(::Any, ::Nothing)
# isequal(::UUID, ::Any)
# cmp(::AbstractString, ::String)
# convert(::Type{Int}, ::Integer)
# convert(::Type{UInt}, ::Integer)
# convert(::Type{Union{Nothing,Module}}, ::Any)
# Base.to_index(::Integer)
# iterate(::Base.OneTo, ::Any)
# repr(::Any)
# thisind(::AbstractString, ::Int)
# getindex(::String, ::Any)
# string(::String, ::Integer, ::String)
# ^(::String, ::Integer)
# repeat(::String, ::Integer)
# Base.isidentifier(::AbstractString)
# +(::Ptr{UInt8}, ::Integer)
# Base._show_default(::Base.GenericIOBuffer{Array{UInt8,1}}, ::Any)

# Ones that are better but I don't remember helping with
# isconcretetype(::Any)
# pointer(::String, ::Integer)

# Regressions:
# basename(::AbstractString)
# splitdir(::AbstractString)
# isfile(::Any)
# joinpath(::AbstractString, ::String)
# sizeof(::Unsigned)
# +(::Int, ::Any, ::Any)
# Base.split_sign(::Integer)
# in(::Any, ::Tuple{Symbol})
129 changes: 129 additions & 0 deletions demos/abstract_gen_data.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using MethodAnalysis

# Analyze MethodInstance signatures and select those that seem at risk for being invalidated.
function atrisktype(@nospecialize(typ))
# signatures like `convert(Vector, a)`, `foo(::Vararg{Synbol,N}) where N` do not seem to pose a problem
isa(typ, TypeVar) && return false
# isbits parameters are not a problem
isa(typ, Type) || return false
if isa(typ, UnionAll)
typ = Base.unwrap_unionall(typ)
end
# Exclude signatures with Union{}
typ === Union{} && return false
isa(typ, Union) && return atrisktype(typ.a) | atrisktype(typ.b)
# Type{T}: signatures like `convert(::Type{AbstractString}, ::String)` are not problematic, so mark Type as OK
typ <: Type && return false
if typ <: Tuple && length(typ.parameters) >= 1
p1 = typ.parameters[1]
# Constructor calls are not themselves a problem (any `convert`s they trigger might be, but those are covered)
isa(p1, Type) && p1 <: Type && return false
# convert(::Type{T}, ::S) where S<:T is not problematic
if p1 === typeof(Base.convert) || p1 === typeof(Core.convert) || p1 === typeof(Core.Compiler.convert)
p2, p3 = typ.parameters[2], typ.parameters[3]
if isa(p2, Type)
p2 = Base.unwrap_unionall(p2)
if isa(p2, DataType) && length(p2.parameters) === 1
T = p2.parameters[1]
isa(p3, Type) && isa(T, Type) && p3 <: T && return false
end
end
# `getindex`, `length`, etc are OK for various Tuple{T1,T2,...}
elseif (p1 === typeof(Base.getindex) || p1 === typeof(Core.Compiler.getindex)) ||
(p1 === typeof(Base.length) || p1 === typeof(Core.Compiler.length)) ||
(p1 === typeof(Base.isempty) || p1 === typeof(Core.Compiler.isempty)) ||
(p1 === typeof(Base.iterate) || p1 === typeof(Core.iterate) || p1 === typeof(Core.Compiler.iterate))
p2 = typ.parameters[2]
if isa(p2, Type)
p2 = Base.unwrap_unionall(p2)
p2 <: Tuple && return false
end
# show(io::IO, x) is OK as long as typeof(x) is safe
elseif p1 === typeof(Base.show)
atrisktype(typ.parameters[2]) && return true
length(typ.parameters) == 3 && atrisktype(typ.parameters[3]) && return true
return false
end
end
# Standard DataTypes
isconcretetype(typ) && return false
# ::Function args are excluded
typ === Function && return false
!isempty(typ.parameters) && (any(atrisktype, typ.parameters) || return false)
return true
end

# A few tests
@assert atrisktype(Tuple{typeof(==),Any,Any})
@assert atrisktype(Tuple{typeof(==),Symbol,Any})
@assert atrisktype(Tuple{typeof(==),Any,Symbol})
@assert !atrisktype(Tuple{typeof(==),Symbol,Symbol})
@assert !atrisktype(Tuple{typeof(convert),Type{Any},Any})
@assert !atrisktype(Tuple{typeof(convert),Type{AbstractString},AbstractString})
@assert !atrisktype(Tuple{typeof(convert),Type{AbstractString},String})
@assert atrisktype(Tuple{typeof(convert),Type{String},AbstractString})
@assert !atrisktype(Tuple{typeof(map),Function,Vector{Any}})
@assert !atrisktype(Tuple{typeof(getindex),Dict{Union{String,Int},Any},Union{String,Int}})
@assert atrisktype(Tuple{typeof(getindex),Dict{Union{String,Int},Any},Any})
@assert !atrisktype(Tuple{Type{BoundsError},Any,Any})
@assert atrisktype(Tuple{typeof(sin),Any})
@assert !atrisktype(Tuple{typeof(length),Tuple{Any,Any}})

function collect_mis(m::Method)
list = Core.MethodInstance[]
visit(m) do item
if isa(item, Core.MethodInstance)
push!(list, item)
return false
end
return true
end
return list
end

const mis = Dict{Method,Vector{Core.MethodInstance}}()
visit() do item
if item isa Method
m = item
mis[m] = collect_mis(m)
return false
end
return true
end

# Count # of backedges for MethodInstances with abstract types
const becounter = Dict{Core.MethodInstance,Int}()
visit() do item
if item isa Core.MethodInstance
if atrisktype(item.specTypes)
becounter[item] = length(all_backedges(item))
end
return false
end
return true
end

prs = sort!(collect(becounter); by=last)

# Organize them by method instead

const mcounter = Dict{Method,Int}()
for (mi, c) in becounter
oc = get(mcounter, mi.def, 0)
mcounter[mi.def] = oc + c
end

mprs = sort!(collect(mcounter); by=last)

open("/tmp/methinstdata_$VERSION.log", "w") do io
for (mi, c) in prs
c == 0 && continue
println(io, mi.specTypes=>c)
end
end
open("/tmp/methdata_$VERSION.log", "w") do io
for (m, c) in mprs
c == 0 && continue
println(io, m.sig=>c)
end
end
Loading