Skip to content

Commit

Permalink
Keyless maps default to BPF_MAP_TYPE_ARRAY for some types (#3300)
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelnair authored Jul 22, 2024
1 parent 44019ba commit b4a70de
Show file tree
Hide file tree
Showing 127 changed files with 4,545 additions and 5,498 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ and this project adheres to
- [#3203](https://github.com/bpftrace/bpftrace/pull/3203)
- Remove length limitations for the `buf` builtin function
- [#3249](https://github.com/bpftrace/bpftrace/pull/3249)
- Faster map access for keyless maps by using BPF_MAP_TYPE_ARRAY
- [#3300](https://github.com/bpftrace/bpftrace/pull/3300)
#### Deprecated
#### Removed
- Remove the `-dd` CLI option
Expand Down
16 changes: 12 additions & 4 deletions src/ast/dibuilderbpf.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "dibuilderbpf.h"

#include "libbpf/bpf.h"
#include "log.h"
#include "struct.h"
#include "utils.h"
Expand Down Expand Up @@ -204,12 +205,17 @@ DIType *DIBuilderBPF::GetType(const SizedType &stype)
}

DIType *DIBuilderBPF::GetMapKeyType(const MapKey &key,
const SizedType &value_type)
const SizedType &value_type,
libbpf::bpf_map_type map_type)
{
// No-key maps use '0' as the key.
// No-key count() maps use BPF_MAP_TYPE_PERCPU_ARRAY which needs 4-byte key.
// - BPF requires 4-byte keys for array maps
// - bpftrace uses 8 bytes for the implicit '0' key in hash maps
if (key.args_.size() == 0)
return value_type.IsCountTy() ? getInt32Ty() : getInt64Ty();
return (map_type == libbpf::BPF_MAP_TYPE_PERCPU_ARRAY ||
map_type == libbpf::BPF_MAP_TYPE_ARRAY)
? getInt32Ty()
: getInt64Ty();

// Some map types need an extra 8-byte key.
uint64_t extra_arg_size = 0;
Expand Down Expand Up @@ -261,7 +267,9 @@ DIGlobalVariableExpression *DIBuilderBPF::createMapEntry(
uint64_t size = 128;
if (!value_type.IsNoneTy()) {
fields.push_back(createPointerMemberType(
"key", size, createPointerType(GetMapKeyType(key, value_type), 64)));
"key",
size,
createPointerType(GetMapKeyType(key, value_type, map_type), 64)));
fields.push_back(createPointerMemberType(
"value", size + 64, createPointerType(GetType(value_type), 64)));
size += 128;
Expand Down
4 changes: 3 additions & 1 deletion src/ast/dibuilderbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ class DIBuilderBPF : public DIBuilder {
DIType *createPointerMemberType(const std::string &name,
uint64_t offset,
DIType *type);
DIType *GetMapKeyType(const MapKey &key, const SizedType &value_type);
DIType *GetMapKeyType(const MapKey &key,
const SizedType &value_type,
libbpf::bpf_map_type map_type);
DIType *GetMapFieldInt(int value);
DIGlobalVariableExpression *createMapEntry(const std::string &name,
libbpf::bpf_map_type map_type,
Expand Down
14 changes: 9 additions & 5 deletions src/ast/passes/codegen_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3519,11 +3519,10 @@ libbpf::bpf_map_type CodegenLLVM::get_map_type(const SizedType &val_type,
if (val_type.IsCountTy() && key.args_.empty()) {
return libbpf::BPF_MAP_TYPE_PERCPU_ARRAY;
} else if (bpftrace_.feature_->has_map_percpu_hash() &&
(val_type.IsHistTy() || val_type.IsLhistTy() ||
val_type.IsCountTy() || val_type.IsSumTy() ||
val_type.IsMinTy() || val_type.IsMaxTy() || val_type.IsAvgTy() ||
val_type.IsStatsTy())) {
val_type.NeedsPercpuMap()) {
return libbpf::BPF_MAP_TYPE_PERCPU_HASH;
} else if (!val_type.NeedsPercpuMap() && key.args_.empty()) {
return libbpf::BPF_MAP_TYPE_ARRAY;
} else {
return libbpf::BPF_MAP_TYPE_HASH;
}
Expand Down Expand Up @@ -3563,7 +3562,12 @@ void CodegenLLVM::generate_maps(const RequiredResources &resources)

auto max_entries = bpftrace_.config_.get(ConfigKeyInt::max_map_keys);
auto map_type = get_map_type(val_type, key);
if (val_type.IsCountTy() && key.args_.empty()) {
// This is special casing for keyless maps eg: @x or @++. For a subset of
// keyless maps we can special case them to BPF_MAP_TYPE_ARRAY instead of
// HASH for efficiency
if ((map_type == libbpf::BPF_MAP_TYPE_PERCPU_ARRAY ||
map_type == libbpf::BPF_MAP_TYPE_ARRAY) &&
key.args_.empty()) {
max_entries = 1;
}

Expand Down
5 changes: 5 additions & 0 deletions src/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,11 @@ bool SizedType::FitsInto(const SizedType &t) const
return IsEqual(t);
}

bool SizedType::NeedsPercpuMap() const
{
return IsHistTy() || IsLhistTy() || IsCountTy() || IsSumTy() || IsMinTy() ||
IsMaxTy() || IsAvgTy() || IsStatsTy();
}
} // namespace bpftrace

namespace std {
Expand Down
2 changes: 2 additions & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ class SizedType {
type_ == Type::lhist || type_ == Type::stats);
}

bool NeedsPercpuMap() const;

friend std::ostream &operator<<(std::ostream &, const SizedType &);
friend std::ostream &operator<<(std::ostream &, Type);

Expand Down
93 changes: 42 additions & 51 deletions tests/codegen/llvm/basic_while_loop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ target triple = "bpf-pc-linux"

@LICENSE = global [4 x i8] c"GPL\00", section "license"
@AT_ = dso_local global %"struct map_t" zeroinitializer, section ".maps", !dbg !0
@ringbuf = dso_local global %"struct map_t.0" zeroinitializer, section ".maps", !dbg !20
@event_loss_counter = dso_local global %"struct map_t.1" zeroinitializer, section ".maps", !dbg !34
@ringbuf = dso_local global %"struct map_t.0" zeroinitializer, section ".maps", !dbg !22
@event_loss_counter = dso_local global %"struct map_t.1" zeroinitializer, section ".maps", !dbg !36

; Function Attrs: nounwind
declare i64 @llvm.bpf.pseudo(i64 %0, i64 %1) #0

define i64 @interval_s_1_1(ptr %0) section "s_interval_s_1_1" !dbg !50 {
define i64 @interval_s_1_1(ptr %0) section "s_interval_s_1_1" !dbg !41 {
entry:
%"@_val" = alloca i64, align 8
%"@_key" = alloca i64, align 8
Expand All @@ -30,7 +30,7 @@ while_cond: ; preds = %while_body, %entry
%2 = icmp sle i64 %1, 150
%3 = zext i1 %2 to i64
%true_cond = icmp ne i64 %3, 0
br i1 %true_cond, label %while_body, label %while_end, !llvm.loop !57
br i1 %true_cond, label %while_body, label %while_end, !llvm.loop !48

while_body: ; preds = %while_cond
%4 = load i64, ptr %"$a", align 8
Expand Down Expand Up @@ -58,8 +58,8 @@ declare void @llvm.lifetime.end.p0(i64 immarg %0, ptr nocapture %1) #1
attributes #0 = { nounwind }
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }

!llvm.dbg.cu = !{!47}
!llvm.module.flags = !{!49}
!llvm.dbg.cu = !{!38}
!llvm.module.flags = !{!40}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "AT_", linkageName: "global", scope: !2, file: !2, type: !3, isLocal: false, isDefinition: true)
Expand All @@ -68,55 +68,46 @@ attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: re
!4 = !{!5, !11, !16, !19}
!5 = !DIDerivedType(tag: DW_TAG_member, name: "type", scope: !2, file: !2, baseType: !6, size: 64)
!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
!7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 32, elements: !9)
!7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 64, elements: !9)
!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!9 = !{!10}
!10 = !DISubrange(count: 1, lowerBound: 0)
!10 = !DISubrange(count: 2, lowerBound: 0)
!11 = !DIDerivedType(tag: DW_TAG_member, name: "max_entries", scope: !2, file: !2, baseType: !12, size: 64, offset: 64)
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
!13 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 131072, elements: !14)
!13 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 32, elements: !14)
!14 = !{!15}
!15 = !DISubrange(count: 4096, lowerBound: 0)
!15 = !DISubrange(count: 1, lowerBound: 0)
!16 = !DIDerivedType(tag: DW_TAG_member, name: "key", scope: !2, file: !2, baseType: !17, size: 64, offset: 128)
!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)
!18 = !DIBasicType(name: "int64", size: 64, encoding: DW_ATE_signed)
!19 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !2, file: !2, baseType: !17, size: 64, offset: 192)
!20 = !DIGlobalVariableExpression(var: !21, expr: !DIExpression())
!21 = distinct !DIGlobalVariable(name: "ringbuf", linkageName: "global", scope: !2, file: !2, type: !22, isLocal: false, isDefinition: true)
!22 = !DICompositeType(tag: DW_TAG_structure_type, scope: !2, file: !2, size: 128, elements: !23)
!23 = !{!24, !29}
!24 = !DIDerivedType(tag: DW_TAG_member, name: "type", scope: !2, file: !2, baseType: !25, size: 64)
!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !26, size: 64)
!26 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 864, elements: !27)
!27 = !{!28}
!28 = !DISubrange(count: 27, lowerBound: 0)
!29 = !DIDerivedType(tag: DW_TAG_member, name: "max_entries", scope: !2, file: !2, baseType: !30, size: 64, offset: 64)
!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64)
!31 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 8388608, elements: !32)
!32 = !{!33}
!33 = !DISubrange(count: 262144, lowerBound: 0)
!34 = !DIGlobalVariableExpression(var: !35, expr: !DIExpression())
!35 = distinct !DIGlobalVariable(name: "event_loss_counter", linkageName: "global", scope: !2, file: !2, type: !36, isLocal: false, isDefinition: true)
!36 = !DICompositeType(tag: DW_TAG_structure_type, scope: !2, file: !2, size: 256, elements: !37)
!37 = !{!38, !43, !44, !19}
!38 = !DIDerivedType(tag: DW_TAG_member, name: "type", scope: !2, file: !2, baseType: !39, size: 64)
!39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64)
!40 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 64, elements: !41)
!41 = !{!42}
!42 = !DISubrange(count: 2, lowerBound: 0)
!43 = !DIDerivedType(tag: DW_TAG_member, name: "max_entries", scope: !2, file: !2, baseType: !6, size: 64, offset: 64)
!44 = !DIDerivedType(tag: DW_TAG_member, name: "key", scope: !2, file: !2, baseType: !45, size: 64, offset: 128)
!45 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !46, size: 64)
!46 = !DIBasicType(name: "int32", size: 32, encoding: DW_ATE_signed)
!47 = distinct !DICompileUnit(language: DW_LANG_C, file: !2, producer: "bpftrace", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, globals: !48)
!48 = !{!0, !20, !34}
!49 = !{i32 2, !"Debug Info Version", i32 3}
!50 = distinct !DISubprogram(name: "interval_s_1_1", linkageName: "interval_s_1_1", scope: !2, file: !2, type: !51, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !47, retainedNodes: !55)
!51 = !DISubroutineType(types: !52)
!52 = !{!18, !53}
!53 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !54, size: 64)
!54 = !DIBasicType(name: "int8", size: 8, encoding: DW_ATE_signed)
!55 = !{!56}
!56 = !DILocalVariable(name: "ctx", arg: 1, scope: !50, file: !2, type: !53)
!57 = distinct !{!57, !58}
!58 = !{!"llvm.loop.unroll.disable"}
!18 = !DIBasicType(name: "int32", size: 32, encoding: DW_ATE_signed)
!19 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !2, file: !2, baseType: !20, size: 64, offset: 192)
!20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64)
!21 = !DIBasicType(name: "int64", size: 64, encoding: DW_ATE_signed)
!22 = !DIGlobalVariableExpression(var: !23, expr: !DIExpression())
!23 = distinct !DIGlobalVariable(name: "ringbuf", linkageName: "global", scope: !2, file: !2, type: !24, isLocal: false, isDefinition: true)
!24 = !DICompositeType(tag: DW_TAG_structure_type, scope: !2, file: !2, size: 128, elements: !25)
!25 = !{!26, !31}
!26 = !DIDerivedType(tag: DW_TAG_member, name: "type", scope: !2, file: !2, baseType: !27, size: 64)
!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64)
!28 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 864, elements: !29)
!29 = !{!30}
!30 = !DISubrange(count: 27, lowerBound: 0)
!31 = !DIDerivedType(tag: DW_TAG_member, name: "max_entries", scope: !2, file: !2, baseType: !32, size: 64, offset: 64)
!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
!33 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 8388608, elements: !34)
!34 = !{!35}
!35 = !DISubrange(count: 262144, lowerBound: 0)
!36 = !DIGlobalVariableExpression(var: !37, expr: !DIExpression())
!37 = distinct !DIGlobalVariable(name: "event_loss_counter", linkageName: "global", scope: !2, file: !2, type: !3, isLocal: false, isDefinition: true)
!38 = distinct !DICompileUnit(language: DW_LANG_C, file: !2, producer: "bpftrace", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, globals: !39)
!39 = !{!0, !22, !36}
!40 = !{i32 2, !"Debug Info Version", i32 3}
!41 = distinct !DISubprogram(name: "interval_s_1_1", linkageName: "interval_s_1_1", scope: !2, file: !2, type: !42, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !38, retainedNodes: !46)
!42 = !DISubroutineType(types: !43)
!43 = !{!21, !44}
!44 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !45, size: 64)
!45 = !DIBasicType(name: "int8", size: 8, encoding: DW_ATE_signed)
!46 = !{!47}
!47 = !DILocalVariable(name: "ctx", arg: 1, scope: !41, file: !2, type: !44)
!48 = distinct !{!48, !49}
!49 = !{!"llvm.loop.unroll.disable"}
Loading

0 comments on commit b4a70de

Please sign in to comment.