diff --git a/NEWS.md b/NEWS.md index 488be0f3209b4a..7b4cda50b8985d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -118,6 +118,11 @@ Standard library changes * Structured matrices now retain either the axes of the parent (for `Symmetric`/`Hermitian`/`AbstractTriangular`/`UpperHessenberg`), or that of the principal diagonal (for banded matrices) ([#52480]). * `bunchkaufman` and `bunchkaufman!` now work for any `AbstractFloat`, `Rational` and their complex variants. `bunchkaufman` now supports `Integer` types, by making an internal conversion to `Rational{BigInt}`. Added new function `inertia` that computes the inertia of the diagonal factor given by the `BunchKaufman` factorization object of a real symmetric or Hermitian matrix. For complex symmetric matrices, `inertia` only computes the number of zero eigenvalues of the diagonal factor ([#51487]). +#### Logging +* New `@create_log_macro` macro for creating new log macros like `@info`, `@warn` etc. For instance + `@create_log_macro MyLog 1500 :magenta` will create `@mylog` to be used like `@mylog "hello"` which + will show as `┌ MyLog: hello` etc. ([#52196]) + #### Printf #### Profile diff --git a/README.md b/README.md index 6fa264c57ac216..fde5e8ee8a8bda 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ and then use the command prompt to change into the resulting julia directory. By Julia. However, most users should use the [most recent stable version](https://github.com/JuliaLang/julia/releases) of Julia. You can get this version by running: - git checkout v1.9.4 + git checkout v1.10.0 To build the `julia` executable, run `make` from within the julia directory. diff --git a/THIRDPARTY.md b/THIRDPARTY.md index 51950d9e2c6a1b..89d1ce3de3d970 100644 --- a/THIRDPARTY.md +++ b/THIRDPARTY.md @@ -1,5 +1,5 @@ The Julia language is licensed under the MIT License (see [LICENSE.md](./LICENSE.md) ). The "language" consists -of the compiler (the contents of src/), most of the standard library (base/), +of the compiler (the contents of `src/`), most of the standard library (`base/` and `stdlib/`), and some utilities (most of the rest of the files in this repository). See below for exceptions. @@ -26,7 +26,8 @@ own licenses: and optionally: -- [ITTAPI](https://github.com/intel/ittapi/blob/master/LICENSES/BSD-3-Clause.txt) [BSD-3] +- [LibTracyClient](https://github.com/wolfpld/tracy/blob/master/LICENSE) [BSD-3] +- [ITTAPI](https://github.com/intel/ittapi/tree/master/LICENSES) [BSD-3 AND GPL2] Julia's `stdlib` uses the following external libraries, which have their own licenses: @@ -47,8 +48,8 @@ Julia's `stdlib` uses the following external libraries, which have their own lic Julia's build process uses the following external tools: -- [PATCHELF](https://nixos.org/patchelf.html) -- [OBJCONV](https://www.agner.org/optimize/#objconv) +- [PATCHELF](https://github.com/NixOS/patchelf/blob/master/COPYING) [GPL3] +- [OBJCONV](https://www.agner.org/optimize/#objconv) [GPL3] - [LIBWHICH](https://github.com/vtjnash/libwhich/blob/master/LICENSE) [MIT] Julia bundles the following external programs and libraries: diff --git a/base/div.jl b/base/div.jl index 9c2187e662ee9b..8988f2b70f27b0 100644 --- a/base/div.jl +++ b/base/div.jl @@ -22,6 +22,8 @@ See also [`fld`](@ref) and [`cld`](@ref), which are special cases of this functi # Examples: ```jldoctest +julia> div(4, 3, RoundToZero) # Matches div(4, 3) +1 julia> div(4, 3, RoundDown) # Matches fld(4, 3) 1 julia> div(4, 3, RoundUp) # Matches cld(4, 3) diff --git a/base/loading.jl b/base/loading.jl index 1519375099634e..97aa9977a7184f 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2568,7 +2568,7 @@ This can be used to reduce package load times. Cache files are stored in `DEPOT_PATH[1]/compiled`. See [Module initialization and precompilation](@ref) for important notes. """ -function compilecache(pkg::PkgId, internal_stderr::IO = stderr, internal_stdout::IO = stdout; reasons::Union{Dict{String,Int},Nothing}=nothing) +function compilecache(pkg::PkgId, internal_stderr::IO = stderr, internal_stdout::IO = stdout; reasons::Union{Dict{String,Int},Nothing}=Dict{String,Int}()) @nospecialize internal_stderr internal_stdout path = locate_package(pkg) path === nothing && throw(ArgumentError("$pkg not found during precompilation")) @@ -2578,7 +2578,7 @@ end const MAX_NUM_PRECOMPILE_FILES = Ref(10) function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, internal_stdout::IO = stdout, - keep_loaded_modules::Bool = true; reasons::Union{Dict{String,Int},Nothing}=nothing) + keep_loaded_modules::Bool = true; reasons::Union{Dict{String,Int},Nothing}=Dict{String,Int}()) @nospecialize internal_stderr internal_stdout # decide where to put the resulting cache file @@ -3320,11 +3320,12 @@ function list_reasons(reasons::Dict{String,Int}) isempty(reasons) && return "" return "(cache misses: $(join(("$k ($v)" for (k,v) in reasons), ", ")))" end +list_reasons(::Nothing) = "" # returns true if it "cachefile.ji" is stale relative to "modpath.jl" and build_id for modkey # otherwise returns the list of dependencies to also check @constprop :none function stale_cachefile(modpath::String, cachefile::String; ignore_loaded::Bool = false, reasons=nothing) - return stale_cachefile(PkgId(""), UInt128(0), modpath, cachefile; ignore_loaded) + return stale_cachefile(PkgId(""), UInt128(0), modpath, cachefile; ignore_loaded, reasons) end @constprop :none function stale_cachefile(modkey::PkgId, build_id::UInt128, modpath::String, cachefile::String; ignore_loaded::Bool = false, reasons::Union{Dict{String,Int},Nothing}=nothing) diff --git a/base/lock.jl b/base/lock.jl index b473b4033e2dea..e3a84635780748 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -220,6 +220,8 @@ available. When this function returns, the `lock` has been released, so the caller should not attempt to `unlock` it. +See also: [`@lock`](@ref). + !!! compat "Julia 1.7" Using a [`Channel`](@ref) as the second argument requires Julia 1.7 or later. """ diff --git a/base/logging.jl b/base/logging.jl index f6a34aee2f5161..1853caa16148cc 100644 --- a/base/logging.jl +++ b/base/logging.jl @@ -162,14 +162,18 @@ const AboveMaxLevel = LogLevel( 1000001) # Global log limiting mechanism for super fast but inflexible global log limiting. const _min_enabled_level = Ref{LogLevel}(Debug) +# stored as LogLevel => (name, color) +const custom_log_levels = Dict{LogLevel,Tuple{Symbol,Union{Symbol,Int}}}() + function show(io::IO, level::LogLevel) - if level == BelowMinLevel print(io, "BelowMinLevel") - elseif level == Debug print(io, "Debug") - elseif level == Info print(io, "Info") - elseif level == Warn print(io, "Warn") - elseif level == Error print(io, "Error") - elseif level == AboveMaxLevel print(io, "AboveMaxLevel") - else print(io, "LogLevel($(level.level))") + if haskey(custom_log_levels, level) print(io, custom_log_levels[level][1]) + elseif level == BelowMinLevel print(io, "BelowMinLevel") + elseif level == Debug print(io, "Debug") + elseif level == Info print(io, "Info") + elseif level == Warn print(io, "Warn") + elseif level == Error print(io, "Error") + elseif level == AboveMaxLevel print(io, "AboveMaxLevel") + else print(io, "LogLevel($(level.level))") end end diff --git a/doc/src/base/math.md b/doc/src/base/math.md index cb427c9458fe12..cff841d991880a 100644 --- a/doc/src/base/math.md +++ b/doc/src/base/math.md @@ -14,10 +14,12 @@ Base.fma Base.muladd Base.inv(::Number) Base.div +Base.div(::Any, ::Any, ::RoundingMode) Base.fld Base.cld Base.mod Base.rem +Base.rem(::Any, ::Any, ::RoundingMode) Base.rem2pi Base.Math.mod2pi Base.divrem diff --git a/julia.spdx.json b/julia.spdx.json index bea7bdc6c3a5d5..63683dd302a39c 100644 --- a/julia.spdx.json +++ b/julia.spdx.json @@ -370,6 +370,32 @@ "copyrightText": "Copyright © 2014-2019 by Steven G. Johnson, Jiahao Chen, Tony Kelman, Jonas Fonseca, and other contributors listed in the git history.", "summary": "utf8proc is a small, clean C library that provides Unicode normalization, case-folding, and other operations for data in the UTF-8 encoding." }, + { + "name": "LibTracyClient", + "SPDXID": "SPDXRef-LibTracyClient", + "downloadLocation": "git+https://github.com/wolfpld/tracy.git", + "filesAnalyzed": false, + "homepage": "https://github.com/wolfpld/tracy", + "sourceInfo": "The git hash of the version in use can be found in the file deps/libtracyclient.version", + "licenseConcluded": "BSD-3-Clause", + "licenseDeclared": "BSD-3-Clause", + "copyrightText": "Copyright (c) 2017-2024, Bartosz Taudul ", + "summary": "A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling profiler for games and other applications.", + "comment": "LibTracyClient is an optional dependency that is not built by default" + }, + { + "name": "ittapi", + "SPDXID": "SPDXRef-ittapi", + "downloadLocation": "git+https://github.com/intel/ittapi.git", + "filesAnalyzed": false, + "homepage": "https://github.com/intel/ittapi", + "sourceInfo": "The git hash of the version in use can be found in the file deps/ittapi.version", + "licenseConcluded": "BSD-3-Clause AND GPL-2.0-only", + "licenseDeclared": "BSD-3-Clause AND GPL-2.0-only", + "copyrightText": "Copyright (c) 2019 Intel Corporation", + "summary": "The Instrumentation and Tracing Technology (ITT) API enables your application to generate and control the collection of trace data during its execution across different Intel tools.", + "comment": "ITTAPI is an optional dependency that is not built by default" + }, { "name": "7-Zip", "SPDXID": "SPDXRef-7zip", @@ -581,6 +607,16 @@ "relationshipType": "BUILD_DEPENDENCY_OF", "relatedSpdxElement": "SPDXRef-JuliaMain" }, + { + "spdxElementId": "SPDXRef-LibTracyClient", + "relationshipType": "OPTIONAL_DEPENDENCY_OF", + "relatedSpdxElement": "SPDXRef-JuliaMain" + }, + { + "spdxElementId": "SPDXRef-ittapi", + "relationshipType": "OPTIONAL_DEPENDENCY_OF", + "relatedSpdxElement": "SPDXRef-JuliaMain" + }, { "spdxElementId": "SPDXRef-7zip", "relationshipType": "RUNTIME_DEPENDENCY_OF", diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 6f80611a7f3eab..c03700796e72ec 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -3428,8 +3428,7 @@ f(x) = yt(x) (define (type-for-closure-parameterized name P names fields types super) (let ((n (length P)) (s (make-ssavalue))) - `((thunk - (lambda () + `((thunk ,(linearize `(lambda () (() () 0 ()) (block (global ,name) (const ,name) ,@(map (lambda (p n) `(= ,p (call (core TypeVar) ',n (core Any)))) P names) @@ -3440,22 +3439,22 @@ f(x) = yt(x) (call (core _setsuper!) ,s ,super) (= (outerref ,name) ,s) (call (core _typebody!) ,s (call (core svec) ,@types)) - (return (null)))))))) + (return (null))))))))) (define (type-for-closure name fields super) (let ((s (make-ssavalue))) - `((thunk (lambda () - (() () 0 ()) - (block (global ,name) (const ,name) - (= ,s (call (core _structtype) (thismodule) (inert ,name) (call (core svec)) - (call (core svec) ,@(map quotify fields)) - (call (core svec)) - (false) ,(length fields))) - (call (core _setsuper!) ,s ,super) - (= (outerref ,name) ,s) - (call (core _typebody!) ,s - (call (core svec) ,@(map (lambda (v) '(core Box)) fields))) - (return (null)))))))) + `((thunk ,(linearize `(lambda () + (() () 0 ()) + (block (global ,name) (const ,name) + (= ,s (call (core _structtype) (thismodule) (inert ,name) (call (core svec)) + (call (core svec) ,@(map quotify fields)) + (call (core svec)) + (false) ,(length fields))) + (call (core _setsuper!) ,s ,super) + (= (outerref ,name) ,s) + (call (core _typebody!) ,s + (call (core svec) ,@(map (lambda (v) '(core Box)) fields))) + (return (null))))))))) ;; better versions of above, but they get handled wrong in many places ;; need to fix that in order to handle #265 fully (and use the definitions) diff --git a/stdlib/Logging/docs/src/index.md b/stdlib/Logging/docs/src/index.md index 55d24c7ae0a267..882c66af2baef7 100644 --- a/stdlib/Logging/docs/src/index.md +++ b/stdlib/Logging/docs/src/index.md @@ -58,7 +58,7 @@ automatically extracted. Let's examine the user-defined data first: * The *log level* is a broad category for the message that is used for early filtering. There are several standard levels of type [`LogLevel`](@ref); user-defined levels are also possible. - Each is distinct in purpose: + Each built-in log level is distinct in purpose: - [`Logging.Debug`](@ref) (log level -1000) is information intended for the developer of the program. These events are disabled by default. - [`Logging.Info`](@ref) (log level 0) is for general information to the user. @@ -70,6 +70,17 @@ automatically extracted. Let's examine the user-defined data first: Often this log-level is unneeded as throwing an exception can convey all the required information. + You can create logging macros for custom log levels. For instance: + ```julia-repl + julia> using Logging + + julia> @create_log_macro MyLog 200 :magenta + @mylog (macro with 1 method) + + julia> @mylog "hello" + [ MyLog: hello + ``` + * The *message* is an object describing the event. By convention `AbstractString`s passed as messages are assumed to be in markdown format. Other types will be displayed using `print(io, obj)` or `string(obj)` for @@ -298,6 +309,7 @@ Logging.Debug Logging.Info Logging.Warn Logging.Error +Logging.@create_log_macro ``` ### [Processing events with AbstractLogger](@id AbstractLogger-interface) diff --git a/stdlib/Logging/src/ConsoleLogger.jl b/stdlib/Logging/src/ConsoleLogger.jl index 747f8a2b229665..1d45296c907d17 100644 --- a/stdlib/Logging/src/ConsoleLogger.jl +++ b/stdlib/Logging/src/ConsoleLogger.jl @@ -58,6 +58,7 @@ end showvalue(io, ex::Exception) = showerror(io, ex) function default_logcolor(level::LogLevel) + level in keys(custom_log_levels) ? custom_log_levels[level][2] : level < Info ? Base.debug_color() : level < Warn ? Base.info_color() : level < Error ? Base.warn_color() : diff --git a/stdlib/Logging/src/Logging.jl b/stdlib/Logging/src/Logging.jl index 0743c650326cc9..83e93ee396361b 100644 --- a/stdlib/Logging/src/Logging.jl +++ b/stdlib/Logging/src/Logging.jl @@ -21,6 +21,7 @@ for sym in [ Symbol("@warn"), Symbol("@error"), Symbol("@logmsg"), + :custom_log_levels, :with_logger, :current_logger, :global_logger, @@ -29,6 +30,41 @@ for sym in [ @eval const $sym = Base.CoreLogging.$sym end +""" + @create_log_macro(name::Symbol, level::Int, color::Union{Int,Symbol}) + +Creates a custom log macro like `@info`, `@warn` etc. with a given `name`, `level` and +`color`. The macro created is named with the lowercase form of `name` but the given form +is used for the printing. + +The available color keys can be seen by typing `Base.text_colors` in the help mode of the REPL + +```julia-repl +julia> @create_log_macro(:MyLog, 200, :magenta) +@mylog (macro with 1 method) + +julia> @mylog "hello" +[ MyLog: hello +``` +""" +macro create_log_macro(name, level, color) + macro_name = Symbol(lowercase(string(name))) + macro_string = QuoteNode(name) + loglevel = LogLevel(level) + if loglevel in (BelowMinLevel, Debug, Info, Warn, Error, AboveMaxLevel) + throw(ArgumentError("Cannot use the same log level as a built in log macro")) + end + if haskey(custom_log_levels, loglevel) + throw(ArgumentError("Custom log macro already exists for given log level")) + end + quote + $(custom_log_levels)[$(esc(loglevel))] = ($(macro_string), $(esc(color))) + macro $(esc(macro_name))(exs...) + $(Base.CoreLogging.logmsg_code)(($(Base.CoreLogging.@_sourceinfo))..., $(esc(loglevel)), exs...) + end + end +end + # LogLevel aliases (re-)documented here (JuliaLang/julia#40978) """ Debug @@ -67,6 +103,7 @@ export @warn, @error, @logmsg, + @create_log_macro, with_logger, current_logger, global_logger, diff --git a/stdlib/Logging/test/runtests.jl b/stdlib/Logging/test/runtests.jl index 3a793c4e0bc334..e7b3fbca2098d5 100644 --- a/stdlib/Logging/test/runtests.jl +++ b/stdlib/Logging/test/runtests.jl @@ -7,8 +7,8 @@ import Logging: min_enabled_level, shouldlog, handle_message @noinline func1() = backtrace() # see "custom log macro" testset -CustomLog = LogLevel(-500) -macro customlog(exs...) Base.CoreLogging.logmsg_code((Base.CoreLogging.@_sourceinfo)..., esc(CustomLog), exs...) end +@create_log_macro CustomLog1 -500 :magenta +@create_log_macro CustomLog2 1500 1 @testset "Logging" begin @@ -280,16 +280,24 @@ end end @testset "custom log macro" begin - @test_logs (CustomLog, "a") min_level=CustomLog @customlog "a" + llevel = LogLevel(-500) + + @test_logs (llevel, "foo") min_level=llevel @customlog1 "foo" buf = IOBuffer() io = IOContext(buf, :displaysize=>(30,80), :color=>false) - logger = ConsoleLogger(io, CustomLog) + logger = ConsoleLogger(io, llevel) + + with_logger(logger) do + @customlog1 "foo" + end + @test occursin("CustomLog1: foo", String(take!(buf))) + with_logger(logger) do - @customlog "a" + @customlog2 "hello" end - @test occursin("LogLevel(-500): a", String(take!(buf))) + @test occursin("CustomLog2: hello", String(take!(buf))) end end diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index cc29a4503d8105..aad97be6833091 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -1,7 +1,24 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license """ -Profiling support, main entry point is the [`@profile`](@ref) macro. + Profile + +Profiling support. + +## CPU profiling +- `@profile foo()` to profile a specific call. +- `Profile.print()` to print the report. +- `Profile.clear()` to clear the buffer. +- Send a $(Sys.isbsd() ? "SIGINFO (ctrl-t)" : "SIGUSR1") signal to the process to automatically trigger a profile and print. + +## Memory profiling +- `Profile.Allocs.@profile [sample_rate=0.1] foo()` to sample allocations within a specific call. A sample rate of 1.0 will record everything; 0.0 will record nothing. +- `Profile.Allocs.print()` to print the report. +- `Profile.Allocs.clear()` to clear the buffer. + +## Heap profiling +- `Profile.take_heap_snapshot()` to record a `.heapsnapshot` record of the heap. +- Set `JULIA_PROFILE_PEEK_HEAP_SNAPSHOT=true` to capture a heap snapshot when signal $(Sys.isbsd() ? "SIGINFO (ctrl-t)" : "SIGUSR1") is sent. """ module Profile diff --git a/stdlib/Sockets/src/addrinfo.jl b/stdlib/Sockets/src/addrinfo.jl index ac4aef8737d1b8..bf5819f6388c6a 100644 --- a/stdlib/Sockets/src/addrinfo.jl +++ b/stdlib/Sockets/src/addrinfo.jl @@ -122,10 +122,20 @@ end getalladdrinfo(host::AbstractString) = getalladdrinfo(String(host)) """ - getaddrinfo(host::AbstractString, IPAddr=IPv4) -> IPAddr + getaddrinfo(host::AbstractString, IPAddr) -> IPAddr Gets the first IP address of the `host` of the specified `IPAddr` type. -Uses the operating system's underlying getaddrinfo implementation, which may do a DNS lookup. +Uses the operating system's underlying getaddrinfo implementation, which may do +a DNS lookup. + +# Examples +```julia-repl +julia> getaddrinfo("localhost", IPv6) +ip"::1" + +julia> getaddrinfo("localhost", IPv4) +ip"127.0.0.1" +``` """ function getaddrinfo(host::String, T::Type{<:IPAddr}) addrs = getalladdrinfo(host) @@ -137,6 +147,14 @@ function getaddrinfo(host::String, T::Type{<:IPAddr}) throw(DNSError(host, UV_EAI_NONAME)) end getaddrinfo(host::AbstractString, T::Type{<:IPAddr}) = getaddrinfo(String(host), T) + +""" + getaddrinfo(host::AbstractString) -> IPAddr + +Gets the first available IP address of `host`, which may be either an `IPv4` or +`IPv6` address. Uses the operating system's underlying getaddrinfo +implementation, which may do a DNS lookup. +""" function getaddrinfo(host::AbstractString) addrs = getalladdrinfo(String(host)) if !isempty(addrs) diff --git a/test/precompile.jl b/test/precompile.jl index 1ac3999947736d..e655dd03b97983 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -3,7 +3,7 @@ original_depot_path = copy(Base.DEPOT_PATH) original_load_path = copy(Base.LOAD_PATH) -using Test, Distributed, Random +using Test, Distributed, Random, Logging using REPL # doc lookup function Foo_module = :Foo4b3a94a1a081a8cb @@ -579,7 +579,7 @@ precompile_test_harness(false) do dir end """) - @test Base.compilecache(Base.PkgId("OverwriteMethodError")) == Base.PrecompilableError() # due to piracy + @test (@test_warn "overwritten in module OverwriteMethodError" Base.compilecache(Base.PkgId("OverwriteMethodError"))) == Base.PrecompilableError() # due to piracy UseBaz_file = joinpath(dir, "UseBaz.jl") write(UseBaz_file, @@ -624,7 +624,7 @@ precompile_test_harness(false) do dir end """) - cachefile, _ = Base.compilecache(Base.PkgId("FooBar")) + cachefile, _ = @test_logs (:debug, r"Precompiling FooBar") min_level=Logging.Debug match_mode=:any Base.compilecache(Base.PkgId("FooBar")) empty_prefs_hash = Base.get_preferences_hash(nothing, String[]) @test cachefile == Base.compilecache_path(Base.PkgId("FooBar"), empty_prefs_hash) @test isfile(joinpath(cachedir, "FooBar.ji"))