VirtualBox

source: vbox/trunk/src/VBox/Additions/3D/mesa/mesa-24.0.2/.gitlab-ci/common/intel-gpu-freq.sh@ 103996

Last change on this file since 103996 was 103996, checked in by vboxsync, 13 months ago

Additions/3D/mesa: export mesa-24.0.2 to OSE. bugref:10606

File size: 18.8 KB
Line 
1#!/usr/bin/env bash
2# shellcheck disable=SC2013
3# shellcheck disable=SC2015
4# shellcheck disable=SC2034
5# shellcheck disable=SC2046
6# shellcheck disable=SC2059
7# shellcheck disable=SC2086 # we want word splitting
8# shellcheck disable=SC2154
9# shellcheck disable=SC2155
10# shellcheck disable=SC2162
11# shellcheck disable=SC2229
12#
13# This is an utility script to manage Intel GPU frequencies.
14# It can be used for debugging performance problems or trying to obtain a stable
15# frequency while benchmarking.
16#
17# Note the Intel i915 GPU driver allows to change the minimum, maximum and boost
18# frequencies in steps of 50 MHz via:
19#
20# /sys/class/drm/card<n>/<freq_info>
21#
22# Where <n> is the DRM card index and <freq_info> one of the following:
23#
24# - gt_max_freq_mhz (enforced maximum freq)
25# - gt_min_freq_mhz (enforced minimum freq)
26# - gt_boost_freq_mhz (enforced boost freq)
27#
28# The hardware capabilities can be accessed via:
29#
30# - gt_RP0_freq_mhz (supported maximum freq)
31# - gt_RPn_freq_mhz (supported minimum freq)
32# - gt_RP1_freq_mhz (most efficient freq)
33#
34# The current frequency can be read from:
35# - gt_act_freq_mhz (the actual GPU freq)
36# - gt_cur_freq_mhz (the last requested freq)
37#
38# Also note that in addition to GPU management, the script offers the
39# possibility to adjust CPU operating frequencies. However, this is currently
40# limited to just setting the maximum scaling frequency as percentage of the
41# maximum frequency allowed by the hardware.
42#
43# Copyright (C) 2022 Collabora Ltd.
44# Author: Cristian Ciocaltea <[email protected]>
45#
46# SPDX-License-Identifier: MIT
47#
48
49#
50# Constants
51#
52
53# GPU
54DRM_FREQ_SYSFS_PATTERN="/sys/class/drm/card%d/gt_%s_freq_mhz"
55ENF_FREQ_INFO="max min boost"
56CAP_FREQ_INFO="RP0 RPn RP1"
57ACT_FREQ_INFO="act cur"
58THROTT_DETECT_SLEEP_SEC=2
59THROTT_DETECT_PID_FILE_PATH=/tmp/thrott-detect.pid
60
61# CPU
62CPU_SYSFS_PREFIX=/sys/devices/system/cpu
63CPU_PSTATE_SYSFS_PATTERN="${CPU_SYSFS_PREFIX}/intel_pstate/%s"
64CPU_FREQ_SYSFS_PATTERN="${CPU_SYSFS_PREFIX}/cpu%s/cpufreq/%s_freq"
65CAP_CPU_FREQ_INFO="cpuinfo_max cpuinfo_min"
66ENF_CPU_FREQ_INFO="scaling_max scaling_min"
67ACT_CPU_FREQ_INFO="scaling_cur"
68
69#
70# Global variables.
71#
72unset INTEL_DRM_CARD_INDEX
73unset GET_ACT_FREQ GET_ENF_FREQ GET_CAP_FREQ
74unset SET_MIN_FREQ SET_MAX_FREQ
75unset MONITOR_FREQ
76unset CPU_SET_MAX_FREQ
77unset DETECT_THROTT
78unset DRY_RUN
79
80#
81# Simple printf based stderr logger.
82#
83log() {
84 local msg_type=$1
85
86 shift
87 printf "%s: %s: " "${msg_type}" "${0##*/}" >&2
88 printf "$@" >&2
89 printf "\n" >&2
90}
91
92#
93# Helper to print sysfs path for the given card index and freq info.
94#
95# arg1: Frequency info sysfs name, one of *_FREQ_INFO constants above
96# arg2: Video card index, defaults to INTEL_DRM_CARD_INDEX
97#
98print_freq_sysfs_path() {
99 printf ${DRM_FREQ_SYSFS_PATTERN} "${2:-${INTEL_DRM_CARD_INDEX}}" "$1"
100}
101
102#
103# Helper to set INTEL_DRM_CARD_INDEX for the first identified Intel video card.
104#
105identify_intel_gpu() {
106 local i=0 vendor path
107
108 while [ ${i} -lt 16 ]; do
109 [ -c "/dev/dri/card$i" ] || {
110 i=$((i + 1))
111 continue
112 }
113
114 path=$(print_freq_sysfs_path "" ${i})
115 path=${path%/*}/device/vendor
116
117 [ -r "${path}" ] && read vendor < "${path}" && \
118 [ "${vendor}" = "0x8086" ] && INTEL_DRM_CARD_INDEX=$i && return 0
119
120 i=$((i + 1))
121 done
122
123 return 1
124}
125
126#
127# Read the specified freq info from sysfs.
128#
129# arg1: Flag (y/n) to also enable printing the freq info.
130# arg2...: Frequency info sysfs name(s), see *_FREQ_INFO constants above
131# return: Global variable(s) FREQ_${arg} containing the requested information
132#
133read_freq_info() {
134 local var val info path print=0 ret=0
135
136 [ "$1" = "y" ] && print=1
137 shift
138
139 while [ $# -gt 0 ]; do
140 info=$1
141 shift
142 var=FREQ_${info}
143 path=$(print_freq_sysfs_path "${info}")
144
145 [ -r ${path} ] && read ${var} < ${path} || {
146 log ERROR "Failed to read freq info from: %s" "${path}"
147 ret=1
148 continue
149 }
150
151 [ -n "${var}" ] || {
152 log ERROR "Got empty freq info from: %s" "${path}"
153 ret=1
154 continue
155 }
156
157 [ ${print} -eq 1 ] && {
158 eval val=\$${var}
159 printf "%6s: %4s MHz\n" "${info}" "${val}"
160 }
161 done
162
163 return ${ret}
164}
165
166#
167# Display requested info.
168#
169print_freq_info() {
170 local req_freq
171
172 [ -n "${GET_CAP_FREQ}" ] && {
173 printf "* Hardware capabilities\n"
174 read_freq_info y ${CAP_FREQ_INFO}
175 printf "\n"
176 }
177
178 [ -n "${GET_ENF_FREQ}" ] && {
179 printf "* Enforcements\n"
180 read_freq_info y ${ENF_FREQ_INFO}
181 printf "\n"
182 }
183
184 [ -n "${GET_ACT_FREQ}" ] && {
185 printf "* Actual\n"
186 read_freq_info y ${ACT_FREQ_INFO}
187 printf "\n"
188 }
189}
190
191#
192# Helper to print frequency value as requested by user via '-s, --set' option.
193# arg1: user requested freq value
194#
195compute_freq_set() {
196 local val
197
198 case "$1" in
199 +)
200 val=${FREQ_RP0}
201 ;;
202 -)
203 val=${FREQ_RPn}
204 ;;
205 *%)
206 val=$((${1%?} * FREQ_RP0 / 100))
207 # Adjust freq to comply with 50 MHz increments
208 val=$((val / 50 * 50))
209 ;;
210 *[!0-9]*)
211 log ERROR "Cannot set freq to invalid value: %s" "$1"
212 return 1
213 ;;
214 "")
215 log ERROR "Cannot set freq to unspecified value"
216 return 1
217 ;;
218 *)
219 # Adjust freq to comply with 50 MHz increments
220 val=$(($1 / 50 * 50))
221 ;;
222 esac
223
224 printf "%s" "${val}"
225}
226
227#
228# Helper for set_freq().
229#
230set_freq_max() {
231 log INFO "Setting GPU max freq to %s MHz" "${SET_MAX_FREQ}"
232
233 read_freq_info n min || return $?
234
235 [ ${SET_MAX_FREQ} -gt ${FREQ_RP0} ] && {
236 log ERROR "Cannot set GPU max freq (%s) to be greater than hw max freq (%s)" \
237 "${SET_MAX_FREQ}" "${FREQ_RP0}"
238 return 1
239 }
240
241 [ ${SET_MAX_FREQ} -lt ${FREQ_RPn} ] && {
242 log ERROR "Cannot set GPU max freq (%s) to be less than hw min freq (%s)" \
243 "${SET_MIN_FREQ}" "${FREQ_RPn}"
244 return 1
245 }
246
247 [ ${SET_MAX_FREQ} -lt ${FREQ_min} ] && {
248 log ERROR "Cannot set GPU max freq (%s) to be less than min freq (%s)" \
249 "${SET_MAX_FREQ}" "${FREQ_min}"
250 return 1
251 }
252
253 [ -z "${DRY_RUN}" ] || return 0
254
255 if ! printf "%s" ${SET_MAX_FREQ} | tee $(print_freq_sysfs_path max) \
256 $(print_freq_sysfs_path boost) > /dev/null;
257 then
258 log ERROR "Failed to set GPU max frequency"
259 return 1
260 fi
261}
262
263#
264# Helper for set_freq().
265#
266set_freq_min() {
267 log INFO "Setting GPU min freq to %s MHz" "${SET_MIN_FREQ}"
268
269 read_freq_info n max || return $?
270
271 [ ${SET_MIN_FREQ} -gt ${FREQ_max} ] && {
272 log ERROR "Cannot set GPU min freq (%s) to be greater than max freq (%s)" \
273 "${SET_MIN_FREQ}" "${FREQ_max}"
274 return 1
275 }
276
277 [ ${SET_MIN_FREQ} -lt ${FREQ_RPn} ] && {
278 log ERROR "Cannot set GPU min freq (%s) to be less than hw min freq (%s)" \
279 "${SET_MIN_FREQ}" "${FREQ_RPn}"
280 return 1
281 }
282
283 [ -z "${DRY_RUN}" ] || return 0
284
285 if ! printf "%s" ${SET_MIN_FREQ} > $(print_freq_sysfs_path min);
286 then
287 log ERROR "Failed to set GPU min frequency"
288 return 1
289 fi
290}
291
292#
293# Set min or max or both GPU frequencies to the user indicated values.
294#
295set_freq() {
296 # Get hw max & min frequencies
297 read_freq_info n RP0 RPn || return $?
298
299 [ -z "${SET_MAX_FREQ}" ] || {
300 SET_MAX_FREQ=$(compute_freq_set "${SET_MAX_FREQ}")
301 [ -z "${SET_MAX_FREQ}" ] && return 1
302 }
303
304 [ -z "${SET_MIN_FREQ}" ] || {
305 SET_MIN_FREQ=$(compute_freq_set "${SET_MIN_FREQ}")
306 [ -z "${SET_MIN_FREQ}" ] && return 1
307 }
308
309 #
310 # Ensure correct operation order, to avoid setting min freq
311 # to a value which is larger than max freq.
312 #
313 # E.g.:
314 # crt_min=crt_max=600; new_min=new_max=700
315 # > operation order: max=700; min=700
316 #
317 # crt_min=crt_max=600; new_min=new_max=500
318 # > operation order: min=500; max=500
319 #
320 if [ -n "${SET_MAX_FREQ}" ] && [ -n "${SET_MIN_FREQ}" ]; then
321 [ ${SET_MAX_FREQ} -lt ${SET_MIN_FREQ} ] && {
322 log ERROR "Cannot set GPU max freq to be less than min freq"
323 return 1
324 }
325
326 read_freq_info n min || return $?
327
328 if [ ${SET_MAX_FREQ} -lt ${FREQ_min} ]; then
329 set_freq_min || return $?
330 set_freq_max
331 else
332 set_freq_max || return $?
333 set_freq_min
334 fi
335 elif [ -n "${SET_MAX_FREQ}" ]; then
336 set_freq_max
337 elif [ -n "${SET_MIN_FREQ}" ]; then
338 set_freq_min
339 else
340 log "Unexpected call to set_freq()"
341 return 1
342 fi
343}
344
345#
346# Helper for detect_throttling().
347#
348get_thrott_detect_pid() {
349 [ -e ${THROTT_DETECT_PID_FILE_PATH} ] || return 0
350
351 local pid
352 read pid < ${THROTT_DETECT_PID_FILE_PATH} || {
353 log ERROR "Failed to read pid from: %s" "${THROTT_DETECT_PID_FILE_PATH}"
354 return 1
355 }
356
357 local proc_path=/proc/${pid:-invalid}/cmdline
358 [ -r ${proc_path} ] && grep -qs "${0##*/}" ${proc_path} && {
359 printf "%s" "${pid}"
360 return 0
361 }
362
363 # Remove orphaned PID file
364 rm -rf ${THROTT_DETECT_PID_FILE_PATH}
365 return 1
366}
367
368#
369# Control detection and reporting of GPU throttling events.
370# arg1: start - run throttle detector in background
371# stop - stop throttle detector process, if any
372# status - verify if throttle detector is running
373#
374detect_throttling() {
375 local pid
376 pid=$(get_thrott_detect_pid)
377
378 case "$1" in
379 status)
380 printf "Throttling detector is "
381 [ -z "${pid}" ] && printf "not running\n" && return 0
382 printf "running (pid=%s)\n" ${pid}
383 ;;
384
385 stop)
386 [ -z "${pid}" ] && return 0
387
388 log INFO "Stopping throttling detector (pid=%s)" "${pid}"
389 kill ${pid}; sleep 1; kill -0 ${pid} 2>/dev/null && kill -9 ${pid}
390 rm -rf ${THROTT_DETECT_PID_FILE_PATH}
391 ;;
392
393 start)
394 [ -n "${pid}" ] && {
395 log WARN "Throttling detector is already running (pid=%s)" ${pid}
396 return 0
397 }
398
399 (
400 read_freq_info n RPn || exit $?
401
402 while true; do
403 sleep ${THROTT_DETECT_SLEEP_SEC}
404 read_freq_info n act min cur || exit $?
405
406 #
407 # The throttling seems to occur when act freq goes below min.
408 # However, it's necessary to exclude the idle states, where
409 # act freq normally reaches RPn and cur goes below min.
410 #
411 [ ${FREQ_act} -lt ${FREQ_min} ] && \
412 [ ${FREQ_act} -gt ${FREQ_RPn} ] && \
413 [ ${FREQ_cur} -ge ${FREQ_min} ] && \
414 printf "GPU throttling detected: act=%s min=%s cur=%s RPn=%s\n" \
415 ${FREQ_act} ${FREQ_min} ${FREQ_cur} ${FREQ_RPn}
416 done
417 ) &
418
419 pid=$!
420 log INFO "Started GPU throttling detector (pid=%s)" ${pid}
421
422 printf "%s\n" ${pid} > ${THROTT_DETECT_PID_FILE_PATH} || \
423 log WARN "Failed to write throttle detector PID file"
424 ;;
425 esac
426}
427
428#
429# Retrieve the list of online CPUs.
430#
431get_online_cpus() {
432 local path cpu_index
433
434 printf "0"
435 for path in $(grep 1 ${CPU_SYSFS_PREFIX}/cpu*/online); do
436 cpu_index=${path##*/cpu}
437 printf " %s" ${cpu_index%%/*}
438 done
439}
440
441#
442# Helper to print sysfs path for the given CPU index and freq info.
443#
444# arg1: Frequency info sysfs name, one of *_CPU_FREQ_INFO constants above
445# arg2: CPU index
446#
447print_cpu_freq_sysfs_path() {
448 printf ${CPU_FREQ_SYSFS_PATTERN} "$2" "$1"
449}
450
451#
452# Read the specified CPU freq info from sysfs.
453#
454# arg1: CPU index
455# arg2: Flag (y/n) to also enable printing the freq info.
456# arg3...: Frequency info sysfs name(s), see *_CPU_FREQ_INFO constants above
457# return: Global variable(s) CPU_FREQ_${arg} containing the requested information
458#
459read_cpu_freq_info() {
460 local var val info path cpu_index print=0 ret=0
461
462 cpu_index=$1
463 [ "$2" = "y" ] && print=1
464 shift 2
465
466 while [ $# -gt 0 ]; do
467 info=$1
468 shift
469 var=CPU_FREQ_${info}
470 path=$(print_cpu_freq_sysfs_path "${info}" ${cpu_index})
471
472 [ -r ${path} ] && read ${var} < ${path} || {
473 log ERROR "Failed to read CPU freq info from: %s" "${path}"
474 ret=1
475 continue
476 }
477
478 [ -n "${var}" ] || {
479 log ERROR "Got empty CPU freq info from: %s" "${path}"
480 ret=1
481 continue
482 }
483
484 [ ${print} -eq 1 ] && {
485 eval val=\$${var}
486 printf "%6s: %4s Hz\n" "${info}" "${val}"
487 }
488 done
489
490 return ${ret}
491}
492
493#
494# Helper to print freq. value as requested by user via '--cpu-set-max' option.
495# arg1: user requested freq value
496#
497compute_cpu_freq_set() {
498 local val
499
500 case "$1" in
501 +)
502 val=${CPU_FREQ_cpuinfo_max}
503 ;;
504 -)
505 val=${CPU_FREQ_cpuinfo_min}
506 ;;
507 *%)
508 val=$((${1%?} * CPU_FREQ_cpuinfo_max / 100))
509 ;;
510 *[!0-9]*)
511 log ERROR "Cannot set CPU freq to invalid value: %s" "$1"
512 return 1
513 ;;
514 "")
515 log ERROR "Cannot set CPU freq to unspecified value"
516 return 1
517 ;;
518 *)
519 log ERROR "Cannot set CPU freq to custom value; use +, -, or % instead"
520 return 1
521 ;;
522 esac
523
524 printf "%s" "${val}"
525}
526
527#
528# Adjust CPU max scaling frequency.
529#
530set_cpu_freq_max() {
531 local target_freq res=0
532 case "${CPU_SET_MAX_FREQ}" in
533 +)
534 target_freq=100
535 ;;
536 -)
537 target_freq=1
538 ;;
539 *%)
540 target_freq=${CPU_SET_MAX_FREQ%?}
541 ;;
542 *)
543 log ERROR "Invalid CPU freq"
544 return 1
545 ;;
546 esac
547
548 local pstate_info=$(printf "${CPU_PSTATE_SYSFS_PATTERN}" max_perf_pct)
549 [ -e "${pstate_info}" ] && {
550 log INFO "Setting intel_pstate max perf to %s" "${target_freq}%"
551 if ! printf "%s" "${target_freq}" > "${pstate_info}";
552 then
553 log ERROR "Failed to set intel_pstate max perf"
554 res=1
555 fi
556 }
557
558 local cpu_index
559 for cpu_index in $(get_online_cpus); do
560 read_cpu_freq_info ${cpu_index} n ${CAP_CPU_FREQ_INFO} || { res=$?; continue; }
561
562 target_freq=$(compute_cpu_freq_set "${CPU_SET_MAX_FREQ}")
563 [ -z "${target_freq}" ] && { res=$?; continue; }
564
565 log INFO "Setting CPU%s max scaling freq to %s Hz" ${cpu_index} "${target_freq}"
566 [ -n "${DRY_RUN}" ] && continue
567
568 if ! printf "%s" ${target_freq} > $(print_cpu_freq_sysfs_path scaling_max ${cpu_index});
569 then
570 res=1
571 log ERROR "Failed to set CPU%s max scaling frequency" ${cpu_index}
572 fi
573 done
574
575 return ${res}
576}
577
578#
579# Show help message.
580#
581print_usage() {
582 cat <<EOF
583Usage: ${0##*/} [OPTION]...
584
585A script to manage Intel GPU frequencies. Can be used for debugging performance
586problems or trying to obtain a stable frequency while benchmarking.
587
588Note Intel GPUs only accept specific frequencies, usually multiples of 50 MHz.
589
590Options:
591 -g, --get [act|enf|cap|all]
592 Get frequency information: active (default), enforced,
593 hardware capabilities or all of them.
594
595 -s, --set [{min|max}=]{FREQUENCY[%]|+|-}
596 Set min or max frequency to the given value (MHz).
597 Append '%' to interpret FREQUENCY as % of hw max.
598 Use '+' or '-' to set frequency to hardware max or min.
599 Omit min/max prefix to set both frequencies.
600
601 -r, --reset Reset frequencies to hardware defaults.
602
603 -m, --monitor [act|enf|cap|all]
604 Monitor the indicated frequencies via 'watch' utility.
605 See '-g, --get' option for more details.
606
607 -d|--detect-thrott [start|stop|status]
608 Start (default operation) the throttling detector
609 as a background process. Use 'stop' or 'status' to
610 terminate the detector process or verify its status.
611
612 --cpu-set-max [FREQUENCY%|+|-}
613 Set CPU max scaling frequency as % of hw max.
614 Use '+' or '-' to set frequency to hardware max or min.
615
616 -r, --reset Reset frequencies to hardware defaults.
617
618 --dry-run See what the script will do without applying any
619 frequency changes.
620
621 -h, --help Display this help text and exit.
622EOF
623}
624
625#
626# Parse user input for '-g, --get' option.
627# Returns 0 if a value has been provided, otherwise 1.
628#
629parse_option_get() {
630 local ret=0
631
632 case "$1" in
633 act) GET_ACT_FREQ=1;;
634 enf) GET_ENF_FREQ=1;;
635 cap) GET_CAP_FREQ=1;;
636 all) GET_ACT_FREQ=1; GET_ENF_FREQ=1; GET_CAP_FREQ=1;;
637 -*|"")
638 # No value provided, using default.
639 GET_ACT_FREQ=1
640 ret=1
641 ;;
642 *)
643 print_usage
644 exit 1
645 ;;
646 esac
647
648 return ${ret}
649}
650
651#
652# Validate user input for '-s, --set' option.
653# arg1: input value to be validated
654# arg2: optional flag indicating input is restricted to %
655#
656validate_option_set() {
657 case "$1" in
658 +|-|[0-9]%|[0-9][0-9]%)
659 return 0
660 ;;
661 *[!0-9]*|"")
662 print_usage
663 exit 1
664 ;;
665 esac
666
667 [ -z "$2" ] || { print_usage; exit 1; }
668}
669
670#
671# Parse script arguments.
672#
673[ $# -eq 0 ] && { print_usage; exit 1; }
674
675while [ $# -gt 0 ]; do
676 case "$1" in
677 -g|--get)
678 parse_option_get "$2" && shift
679 ;;
680
681 -s|--set)
682 shift
683 case "$1" in
684 min=*)
685 SET_MIN_FREQ=${1#min=}
686 validate_option_set "${SET_MIN_FREQ}"
687 ;;
688 max=*)
689 SET_MAX_FREQ=${1#max=}
690 validate_option_set "${SET_MAX_FREQ}"
691 ;;
692 *)
693 SET_MIN_FREQ=$1
694 validate_option_set "${SET_MIN_FREQ}"
695 SET_MAX_FREQ=${SET_MIN_FREQ}
696 ;;
697 esac
698 ;;
699
700 -r|--reset)
701 RESET_FREQ=1
702 SET_MIN_FREQ="-"
703 SET_MAX_FREQ="+"
704 ;;
705
706 -m|--monitor)
707 MONITOR_FREQ=act
708 parse_option_get "$2" && MONITOR_FREQ=$2 && shift
709 ;;
710
711 -d|--detect-thrott)
712 DETECT_THROTT=start
713 case "$2" in
714 start|stop|status)
715 DETECT_THROTT=$2
716 shift
717 ;;
718 esac
719 ;;
720
721 --cpu-set-max)
722 shift
723 CPU_SET_MAX_FREQ=$1
724 validate_option_set "${CPU_SET_MAX_FREQ}" restricted
725 ;;
726
727 --dry-run)
728 DRY_RUN=1
729 ;;
730
731 -h|--help)
732 print_usage
733 exit 0
734 ;;
735
736 *)
737 print_usage
738 exit 1
739 ;;
740 esac
741
742 shift
743done
744
745#
746# Main
747#
748RET=0
749
750identify_intel_gpu || {
751 log INFO "No Intel GPU detected"
752 exit 0
753}
754
755[ -n "${SET_MIN_FREQ}${SET_MAX_FREQ}" ] && { set_freq || RET=$?; }
756print_freq_info
757
758[ -n "${DETECT_THROTT}" ] && detect_throttling ${DETECT_THROTT}
759
760[ -n "${CPU_SET_MAX_FREQ}" ] && { set_cpu_freq_max || RET=$?; }
761
762[ -n "${MONITOR_FREQ}" ] && {
763 log INFO "Entering frequency monitoring mode"
764 sleep 2
765 exec watch -d -n 1 "$0" -g "${MONITOR_FREQ}"
766}
767
768exit ${RET}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette